diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2023-09-25 12:36:48 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2023-09-25 12:36:48 +0200 |
commit | 7f147d2ef6edd49defa0c136f44dfdc3c103569e (patch) | |
tree | a4230adf3e98ae1924666cad3896eec3fa7bd92d | |
parent | 0fb41e10c49f446915afdca7be090ea57ee9532d (diff) | |
parent | ead1e3dc15512ae3823972a7f1b00da42af84f8a (diff) | |
download | barebox-master.tar.gz barebox-master.tar.xz |
-rw-r--r-- | arch/arm/mach-zynqmp/firmware-zynqmp.c | 133 | ||||
-rw-r--r-- | common/complete.c | 14 | ||||
-rw-r--r-- | drivers/base/driver.c | 46 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 6 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/cadence_wdt.c | 278 | ||||
-rw-r--r-- | include/driver.h | 7 | ||||
-rw-r--r-- | include/linux/clk.h | 31 | ||||
-rw-r--r-- | include/mach/zynqmp/debug_ll.h | 9 | ||||
-rw-r--r-- | include/mach/zynqmp/firmware-zynqmp.h | 33 |
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_ */ |