summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2023-09-25 12:36:48 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2023-09-25 12:36:48 +0200
commit7f147d2ef6edd49defa0c136f44dfdc3c103569e (patch)
treea4230adf3e98ae1924666cad3896eec3fa7bd92d
parent0fb41e10c49f446915afdca7be090ea57ee9532d (diff)
parentead1e3dc15512ae3823972a7f1b00da42af84f8a (diff)
downloadbarebox-master.tar.gz
barebox-master.tar.xz
Merge branch 'for-next/zynqmp'HEADmaster
-rw-r--r--arch/arm/mach-zynqmp/firmware-zynqmp.c133
-rw-r--r--common/complete.c14
-rw-r--r--drivers/base/driver.c46
-rw-r--r--drivers/watchdog/Kconfig6
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/cadence_wdt.c278
-rw-r--r--include/driver.h7
-rw-r--r--include/linux/clk.h31
-rw-r--r--include/mach/zynqmp/debug_ll.h9
-rw-r--r--include/mach/zynqmp/firmware-zynqmp.h33
10 files changed, 545 insertions, 13 deletions
diff --git a/arch/arm/mach-zynqmp/firmware-zynqmp.c b/arch/arm/mach-zynqmp/firmware-zynqmp.c
index 128f042ddc..a2b61efff4 100644
--- a/arch/arm/mach-zynqmp/firmware-zynqmp.c
+++ b/arch/arm/mach-zynqmp/firmware-zynqmp.c
@@ -14,10 +14,18 @@
#include <common.h>
#include <init.h>
+#include <driver.h>
+#include <param.h>
#include <linux/arm-smccc.h>
#include <mach/zynqmp/firmware-zynqmp.h>
+struct zynqmp_fw {
+ struct device *dev;
+ u32 ggs[4];
+ u32 pggs[4];
+};
+
#define ZYNQMP_TZ_VERSION(MAJOR, MINOR) ((MAJOR << 16) | MINOR)
#define ZYNQMP_PM_VERSION_MAJOR 1
@@ -503,6 +511,72 @@ static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
arg1, arg2, out);
}
+/*
+ * zynqmp_pm_write_ggs() - PM API for writing global general storage (ggs)
+ * @index: GGS register index
+ * @value: Register value to be written
+ *
+ * This function writes value to GGS register.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_write_ggs(u32 index, u32 value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS,
+ index, value, NULL);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
+
+/**
+ * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs)
+ * @index: GGS register index
+ * @value: Register value to be written
+ *
+ * This function returns GGS register value.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_read_ggs(u32 index, u32 *value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS,
+ index, 0, value);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
+
+/**
+ * zynqmp_pm_write_pggs() - PM API for writing persistent global general
+ * storage (pggs)
+ * @index: PGGS register index
+ * @value: Register value to be written
+ *
+ * This function writes value to PGGS register.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_write_pggs(u32 index, u32 value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value,
+ NULL);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
+
+/**
+ * zynqmp_pm_read_pggs() - PM API for reading persistent global general
+ * storage (pggs)
+ * @index: PGGS register index
+ * @value: Register value to be written
+ *
+ * This function returns PGGS register value.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+int zynqmp_pm_read_pggs(u32 index, u32 *value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0,
+ value);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
+
/**
* zynqmp_pm_fpga_load - Perform the fpga load
* @address: Address to write to
@@ -576,11 +650,58 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
+static bool parse_reg(const char *reg, unsigned *idx)
+{
+ bool pggs = reg[0] == 'p';
+ kstrtouint(reg + pggs + sizeof("ggs") - 1, 10, idx);
+ return pggs;
+}
+
+static int ggs_set(struct param_d *p, void *_val)
+{
+ u32 *val = _val;
+ unsigned idx;
+
+ if (parse_reg(p->name, &idx))
+ return zynqmp_pm_write_pggs(idx, *val);
+ else
+ return zynqmp_pm_write_ggs(idx, *val);
+}
+static int ggs_get(struct param_d *p, void *_val)
+{
+ u32 ret_payload[PAYLOAD_ARG_CNT];
+ u32 *val = _val;
+ unsigned idx;
+ int ret;
+
+ if (parse_reg(p->name, &idx))
+ ret = zynqmp_pm_read_pggs(idx, ret_payload);
+ else
+ ret = zynqmp_pm_read_ggs(idx, ret_payload);
+
+ if (ret)
+ return ret;
+
+ *val = ret_payload[1];
+
+ return 0;
+}
+
+static inline void dev_add_param_ggs(struct zynqmp_fw *fw, const char *str, u32 *value)
+{
+ dev_add_param_uint32(fw->dev, str, ggs_set, ggs_get, value, "0x%x", value);
+}
static int zynqmp_firmware_probe(struct device *dev)
{
+
+ struct zynqmp_fw *fw;
int ret;
+ fw = xzalloc(sizeof(*fw));
+
+ dev_add_alias(dev, "zynqmp_fw");
+
ret = get_set_conduit_method(dev->of_node);
if (ret)
goto out;
@@ -620,6 +741,18 @@ static int zynqmp_firmware_probe(struct device *dev)
pm_tz_version >> 16, pm_tz_version & 0xFFFF);
of_platform_populate(dev->of_node, NULL, dev);
+
+ fw->dev = dev;
+
+ dev_add_param_ggs(fw, "ggs0", &fw->ggs[0]);
+ dev_add_param_ggs(fw, "ggs1", &fw->ggs[1]);
+ dev_add_param_ggs(fw, "ggs2", &fw->ggs[2]);
+ dev_add_param_ggs(fw, "ggs3", &fw->ggs[3]);
+
+ dev_add_param_ggs(fw, "pggs0", &fw->pggs[0]);
+ dev_add_param_ggs(fw, "pggs1", &fw->pggs[1]);
+ dev_add_param_ggs(fw, "pggs2", &fw->pggs[2]);
+ dev_add_param_ggs(fw, "pggs3", &fw->pggs[3]);
out:
if (ret)
do_fw_call = do_fw_call_fail;
diff --git a/common/complete.c b/common/complete.c
index e9f3f8ee03..4137bb3084 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -154,8 +154,8 @@ int device_complete(struct string_list *sl, char *instr)
}
EXPORT_SYMBOL(device_complete);
-static int device_param_complete(struct device *dev, struct string_list *sl,
- char *instr, int eval)
+static int device_param_complete(struct device *dev, const char *devname,
+ struct string_list *sl, char *instr, int eval)
{
struct param_d *param;
int len;
@@ -167,7 +167,7 @@ static int device_param_complete(struct device *dev, struct string_list *sl,
continue;
string_list_add_asprintf(sl, "%s%s.%s%c",
- eval ? "$" : "", dev_name(dev), param->name,
+ eval ? "$" : "", devname, param->name,
eval ? ' ' : '=');
}
@@ -308,14 +308,12 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
char *devname;
devname = xstrndup(instr, dot - instr);
-
-
dev = get_device_by_name(devname);
- free(devname);
if (dev)
- device_param_complete(dev, sl, dot + 1, eval);
+ device_param_complete(dev, devname, sl, dot + 1, eval);
+ free(devname);
pos = dot + 1;
}
@@ -323,7 +321,7 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
for_each_device(dev) {
if (!strncmp(instr, dev_name(dev), len))
- device_param_complete(dev, sl, "", eval);
+ device_param_complete(dev, dev_name(dev), sl, "", eval);
}
return 0;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 10d765e1a2..02d8fb0b6f 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -24,6 +24,7 @@
#include <fs.h>
#include <of.h>
#include <linux/list.h>
+#include <linux/overflow.h>
#include <linux/err.h>
#include <complete.h>
#include <pinctrl.h>
@@ -46,6 +47,8 @@ LIST_HEAD(active_device_list);
EXPORT_SYMBOL(active_device_list);
static LIST_HEAD(deferred);
+static LIST_HEAD(device_alias_list);
+
struct device *find_device(const char *str)
{
struct device *dev;
@@ -65,12 +68,18 @@ struct device *find_device(const char *str)
struct device *get_device_by_name(const char *name)
{
struct device *dev;
+ struct device_alias *alias;
for_each_device(dev) {
if(!strcmp(dev_name(dev), name))
return dev;
}
+ list_for_each_entry(alias, &device_alias_list, list) {
+ if(!strcmp(alias->name, name))
+ return alias->dev;
+ }
+
return NULL;
}
@@ -261,6 +270,7 @@ EXPORT_SYMBOL(register_device);
int unregister_device(struct device *old_dev)
{
+ struct device_alias *alias, *at;
struct cdev *cdev, *ct;
struct device *child, *dt;
@@ -271,6 +281,11 @@ int unregister_device(struct device *old_dev)
if (old_dev->driver)
old_dev->bus->remove(old_dev);
+ list_for_each_entry_safe(alias, at, &device_alias_list, list) {
+ if(alias->dev == old_dev)
+ list_del(&alias->list);
+ }
+
list_for_each_entry_safe(child, dt, &old_dev->children, sibling) {
dev_dbg(old_dev, "unregister child %s\n", dev_name(child));
unregister_device(child);
@@ -592,6 +607,37 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(dev_set_name);
+/**
+ * dev_add_alias - add alias for device
+ * @dev: device
+ * @fmt: format string for the device's alias
+ */
+int dev_add_alias(struct device *dev, const char *fmt, ...)
+{
+ va_list va, va_copy;
+ unsigned int len;
+ struct device_alias *alias;
+
+ va_start(va, fmt);
+ va_copy(va_copy, va);
+ len = vsnprintf(NULL, 0, fmt, va_copy);
+ va_end(va_copy);
+
+ alias = malloc(struct_size(alias, name, len + 1));
+ if (!alias)
+ return -ENOMEM;
+
+ vsnprintf(alias->name, len + 1, fmt, va);
+
+ va_end(va);
+
+ alias->dev = dev;
+ list_add_tail(&alias->list, &device_alias_list);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dev_add_alias);
+
static void devices_shutdown(void)
{
struct device *dev;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6f209e096e..e5c2036e6d 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -165,4 +165,10 @@ config WDAT_WDT
found on some desktop machines as well. This driver will take
over the native iTCO watchdog driver found on many Intel CPUs.
+config CADENCE_WATCHDOG
+ tristate "Cadence Watchdog Timer"
+ help
+ Say Y here if you want to include support for the watchdog
+ timer in the Xilinx Zynq.
+
endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 265ae179f1..cdd9460e34 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o
obj-$(CONFIG_WDAT_WDT) += wdat_wdt.o
+obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c
new file mode 100644
index 0000000000..17655a188c
--- /dev/null
+++ b/drivers/watchdog/cadence_wdt.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Cadence WDT driver - Used by Xilinx Zynq
+ *
+ * Copyright (C) 2010 - 2014 Xilinx, Inc.
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <restart.h>
+#include <watchdog.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/reset.h>
+
+/* Supports 1 - 516 sec */
+#define CDNS_WDT_MAX_TIMEOUT 516
+
+/* Restart key */
+#define CDNS_WDT_RESTART_KEY 0x00001999
+
+/* Counter register access key */
+#define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
+
+/* Counter value divisor */
+#define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
+
+/* Clock prescaler value and selection */
+#define CDNS_WDT_PRESCALE_64 64
+#define CDNS_WDT_PRESCALE_512 512
+#define CDNS_WDT_PRESCALE_4096 4096
+#define CDNS_WDT_PRESCALE_SELECT_64 1
+#define CDNS_WDT_PRESCALE_SELECT_512 2
+#define CDNS_WDT_PRESCALE_SELECT_4096 3
+
+/* Input clock frequency */
+#define CDNS_WDT_CLK_10MHZ 10000000
+#define CDNS_WDT_CLK_75MHZ 75000000
+
+/* Counter maximum value */
+#define CDNS_WDT_COUNTER_MAX 0xFFF
+
+/**
+ * struct cdns_wdt - Watchdog device structure
+ * @regs: baseaddress of device
+ * @clk: struct clk * of a clock source
+ * @prescaler: for saving prescaler value
+ * @ctrl_clksel: counter clock prescaler selection
+ * @cdns_wdt_device: watchdog device structure
+ *
+ * Structure containing parameters specific to cadence watchdog.
+ */
+struct cdns_wdt {
+ void __iomem *regs;
+ struct clk *clk;
+ u32 prescaler;
+ u32 ctrl_clksel;
+ struct watchdog cdns_wdt_device;
+ unsigned timeout;
+};
+
+static inline struct cdns_wdt *to_cdns_wdt(struct watchdog *wdd)
+{
+ return container_of(wdd, struct cdns_wdt, cdns_wdt_device);
+}
+
+/* Write access to Registers */
+static inline void cdns_wdt_writereg(struct cdns_wdt *wdt, u32 offset, u32 val)
+{
+ writel_relaxed(val, wdt->regs + offset);
+}
+
+/*************************Register Map**************************************/
+
+/* Register Offsets for the WDT */
+#define CDNS_WDT_ZMR_OFFSET 0x0 /* Zero Mode Register */
+#define CDNS_WDT_CCR_OFFSET 0x4 /* Counter Control Register */
+#define CDNS_WDT_RESTART_OFFSET 0x8 /* Restart Register */
+#define CDNS_WDT_SR_OFFSET 0xC /* Status Register */
+
+/*
+ * Zero Mode Register - This register controls how the time out is indicated
+ * and also contains the access code to allow writes to the register (0xABC).
+ */
+#define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
+#define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
+#define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
+#define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
+#define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
+/*
+ * Counter Control register - This register controls how fast the timer runs
+ * and the reset value and also contains the access code to allow writes to
+ * the register.
+ */
+#define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
+
+/**
+ * cdns_wdt_stop - Stop the watchdog.
+ *
+ * @wdt: cadence watchdog device
+ *
+ * Read the contents of the ZMR register, clear the WDEN bit
+ * in the register and set the access key for successful write.
+ */
+static void cdns_wdt_stop(struct cdns_wdt *wdt)
+{
+ cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
+ CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
+}
+
+/**
+ * cdns_wdt_reload - Reload the watchdog timer (i.e. pat the watchdog).
+ *
+ * @wdt: cadence watchdog device
+ *
+ * Write the restart key value (0x00001999) to the restart register.
+ */
+static void cdns_wdt_reload(struct cdns_wdt *wdt)
+{
+ cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
+ CDNS_WDT_RESTART_KEY);
+}
+
+/**
+ * cdns_wdt_start - Enable and start the watchdog.
+ *
+ * @wdt: cadence watchdog device
+ * @timeout: new timeout
+ *
+ * The counter value is calculated according to the formula:
+ * calculated count = (timeout * clock) / prescaler + 1.
+ * The calculated count is divided by 0x1000 to obtain the field value
+ * to write to counter control register.
+ * Clears the contents of prescaler and counter reset value. Sets the
+ * prescaler to 4096 and the calculated count and access key
+ * to write to CCR Register.
+ * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
+ * or Interrupt signal(IRQEN) with a specified cycles and the access
+ * key to write to ZMR Register.
+ */
+static void cdns_wdt_start(struct cdns_wdt *wdt, unsigned timeout)
+{
+ unsigned int data = 0;
+ unsigned short count;
+ unsigned long clock_f = clk_get_rate(wdt->clk);
+
+ /*
+ * Counter value divisor to obtain the value of
+ * counter reset to be written to control register.
+ */
+ count = (timeout * (clock_f / wdt->prescaler)) /
+ CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
+
+ if (count > CDNS_WDT_COUNTER_MAX)
+ count = CDNS_WDT_COUNTER_MAX;
+
+ cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
+ CDNS_WDT_ZMR_ZKEY_VAL);
+
+ count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
+
+ /* Write counter access key first to be able write to register */
+ data = count | CDNS_WDT_REGISTER_ACCESS_KEY | wdt->ctrl_clksel;
+ cdns_wdt_writereg(wdt, CDNS_WDT_CCR_OFFSET, data);
+ data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
+ CDNS_WDT_ZMR_ZKEY_VAL;
+
+ /* Reset on timeout regardless of what's specified in device tree. */
+ data |= CDNS_WDT_ZMR_RSTEN_MASK;
+ data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
+
+ cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, data);
+ cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
+ CDNS_WDT_RESTART_KEY);
+}
+
+/**
+ * cdns_wdt_settimeout - Set a new timeout value for the watchdog device.
+ *
+ * @wdd: watchdog device
+ * @new_time: new timeout value that needs to be set
+ * Return: 0 on success
+ *
+ * Update the watchdog device timeout with new value which is used when
+ * cdns_wdt_start is called.
+ */
+static int cdns_wdt_settimeout(struct watchdog *wdd,
+ unsigned int new_time)
+{
+ struct cdns_wdt *wdt = to_cdns_wdt(wdd);
+
+ if (new_time > wdd->timeout_max)
+ return -EINVAL;
+
+ if (new_time == 0) {
+ cdns_wdt_stop(wdt);
+ } else if (wdt->timeout != new_time) {
+ cdns_wdt_start(wdt, new_time);
+ wdt->timeout = new_time;
+ } else {
+ cdns_wdt_reload(wdt);
+ }
+
+ return 0;
+}
+
+/************************Platform Operations*****************************/
+/**
+ * cdns_wdt_probe - Probe call for the device.
+ *
+ * @pdev: handle to the platform device structure.
+ * Return: 0 on success, negative error otherwise.
+ *
+ * It does all the memory allocation and registration for the device.
+ */
+static int cdns_wdt_probe(struct device *dev)
+{
+ unsigned long clock_f;
+ struct cdns_wdt *wdt;
+ struct resource *res;
+ struct watchdog *cdns_wdt_device;
+
+ wdt = xzalloc(sizeof(*wdt));
+
+ cdns_wdt_device = &wdt->cdns_wdt_device;
+ cdns_wdt_device->name = "cdns_wdt";
+ cdns_wdt_device->hwdev = dev;
+ cdns_wdt_device->set_timeout = cdns_wdt_settimeout;
+ cdns_wdt_device->timeout_max = CDNS_WDT_MAX_TIMEOUT;
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ wdt->regs = IOMEM(res->start);
+
+ /* We don't service interrupts in barebox, so a watchdog that doesn't
+ * reset the system isn't a useful thing to register
+ */
+ if (!of_property_read_bool(dev->of_node, "reset-on-timeout"))
+ dev_notice(dev, "proceeding as if reset-on-timeout was set\n");
+
+ wdt->clk = clk_get_enabled(dev, NULL);
+ if (IS_ERR(wdt->clk))
+ return dev_err_probe(dev, PTR_ERR(wdt->clk),
+ "input clock not found\n");
+
+ clock_f = clk_get_rate(wdt->clk);
+ if (clock_f <= CDNS_WDT_CLK_75MHZ) {
+ wdt->prescaler = CDNS_WDT_PRESCALE_512;
+ wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
+ } else {
+ wdt->prescaler = CDNS_WDT_PRESCALE_4096;
+ wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
+ }
+
+ return watchdog_register(cdns_wdt_device);
+}
+
+static const struct of_device_id cdns_wdt_of_match[] = {
+ { .compatible = "cdns,wdt-r1p2", },
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, cdns_wdt_of_match);
+
+static struct driver cdns_wdt_driver = {
+ .name = "cdns-wdt",
+ .probe = cdns_wdt_probe,
+ .of_match_table = cdns_wdt_of_match,
+};
+device_platform_driver(cdns_wdt_driver);
+
+MODULE_AUTHOR("Xilinx, Inc.");
+MODULE_DESCRIPTION("Watchdog driver for Cadence WDT");
+MODULE_LICENSE("GPL");
diff --git a/include/driver.h b/include/driver.h
index 2651cddecc..a0234fb6c3 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -101,6 +101,12 @@ struct device {
char *deferred_probe_reason;
};
+struct device_alias {
+ struct device *dev;
+ struct list_head list;
+ char name[];
+};
+
/** @brief Describes a driver present in the system */
struct driver {
/*! The name of this driver. Used to match to
@@ -216,6 +222,7 @@ static inline const char *dev_name(const struct device *dev)
}
int dev_set_name(struct device *dev, const char *fmt, ...);
+int dev_add_alias(struct device *dev, const char *fmt, ...);
/*
* get resource 'num' for a device
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 82022e78e3..61b4ff3127 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -951,4 +951,35 @@ static inline struct clk *clk_get_optional(struct device *dev, const char *id)
return clk;
}
+/**
+ * clk_get_enabled - clk_get() + clk_prepare_enable()
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Return: a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno. The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer. (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * The returned clk (if valid) is enabled.
+ */
+static inline struct clk *clk_get_enabled(struct device *dev, const char *id)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = clk_get(dev, id);
+ if (IS_ERR(clk))
+ return clk;
+
+ ret = clk_enable(clk);
+ if (ret) {
+ clk_put(clk);
+ return ERR_PTR(ret);
+ }
+
+ return clk;
+}
+
#endif
diff --git a/include/mach/zynqmp/debug_ll.h b/include/mach/zynqmp/debug_ll.h
index 7642e37a4e..cc94d3ce54 100644
--- a/include/mach/zynqmp/debug_ll.h
+++ b/include/mach/zynqmp/debug_ll.h
@@ -15,9 +15,9 @@
#define ZYNQMP_UART_STS_TFUL (1 << 4)
#define ZYNQMP_UART_TXDIS (1 << 5)
-static inline void PUTC_LL(int c)
+static inline void cdns_serial_putc(void *ctx, int c)
{
- void __iomem *base = (void __iomem *)ZYNQMP_DEBUG_LL_UART_BASE;
+ void __iomem *base = ctx;
if (readl(base) & ZYNQMP_UART_TXDIS)
return;
@@ -28,4 +28,9 @@ static inline void PUTC_LL(int c)
writel(c, base + 0x30);
}
+static inline void PUTC_LL(int c)
+{
+ cdns_serial_putc(IOMEM(ZYNQMP_DEBUG_LL_UART_BASE), c);
+}
+
#endif /* __MACH_ZYNQMP_DEBUG_LL_H__ */
diff --git a/include/mach/zynqmp/firmware-zynqmp.h b/include/mach/zynqmp/firmware-zynqmp.h
index a04482237d..630677285f 100644
--- a/include/mach/zynqmp/firmware-zynqmp.h
+++ b/include/mach/zynqmp/firmware-zynqmp.h
@@ -28,10 +28,32 @@
#define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3)
enum pm_ioctl_id {
+ IOCTL_GET_RPU_OPER_MODE = 0,
+ IOCTL_SET_RPU_OPER_MODE = 1,
+ IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
+ IOCTL_TCM_COMB_CONFIG = 3,
+ IOCTL_SET_TAPDELAY_BYPASS = 4,
+ IOCTL_SD_DLL_RESET = 6,
+ IOCTL_SET_SD_TAPDELAY = 7,
IOCTL_SET_PLL_FRAC_MODE = 8,
- IOCTL_GET_PLL_FRAC_MODE,
- IOCTL_SET_PLL_FRAC_DATA,
- IOCTL_GET_PLL_FRAC_DATA,
+ IOCTL_GET_PLL_FRAC_MODE = 9,
+ IOCTL_SET_PLL_FRAC_DATA = 10,
+ IOCTL_GET_PLL_FRAC_DATA = 11,
+ IOCTL_WRITE_GGS = 12,
+ IOCTL_READ_GGS = 13,
+ IOCTL_WRITE_PGGS = 14,
+ IOCTL_READ_PGGS = 15,
+ /* Set healthy bit value */
+ IOCTL_SET_BOOT_HEALTH_STATUS = 17,
+ IOCTL_OSPI_MUX_SELECT = 21,
+ /* Register SGI to ATF */
+ IOCTL_REGISTER_SGI = 25,
+ /* Runtime feature configuration */
+ IOCTL_SET_FEATURE_CONFIG = 26,
+ IOCTL_GET_FEATURE_CONFIG = 27,
+ /* Dynamic SD/GEM configuration */
+ IOCTL_SET_SD_CONFIG = 30,
+ IOCTL_SET_GEM_CONFIG = 31,
};
enum pm_query_id {
@@ -77,4 +99,9 @@ struct zynqmp_eemi_ops {
const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
+int zynqmp_pm_write_ggs(u32 index, u32 value);
+int zynqmp_pm_read_ggs(u32 index, u32 *value);
+int zynqmp_pm_write_pggs(u32 index, u32 value);
+int zynqmp_pm_read_pggs(u32 index, u32 *value);
+
#endif /* FIRMWARE_ZYNQMP_H_ */