diff options
| author | Tom Rini <[email protected]> | 2018-07-19 11:48:33 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2018-07-19 11:48:33 -0400 |
| commit | f7e48c54b246c460503e90315d0cd50ccbd586c6 (patch) | |
| tree | 836d7fd9f833b285645a33e457b74be6110a0e08 /drivers | |
| parent | 1adbf2966adebe67de3dd17094749d387604194e (diff) | |
| parent | 577012da71ea9dcf07272c7f458218aa8ab29984 (diff) | |
Merge tag 'xilinx-for-v2018.09' of git://git.denx.de/u-boot-microblaze
Xilinx changes for v2018.09
clk:
- Fix zynqmp clock driver
common:
- Handle CMD_RET_USAGE in cmd_process_error
- Use return macros in cmd_process_error
- Fix duplication of CONFIG_SYS_PROMPT_HUSH_PS2
- Support watchdog in usb_kbd.c
- Fix name usage in usb_kbd.c
- Support systems with non zero memory start initialized from DT only
gpio:
- Add support for manual relocation in uclass
- zynq - use live tree
- zynq - fix match data reading
- zynq - setup bank name
- xilinx - convert driver to DM
microblaze:
- Use generic iounmap/ioremap implementations
- Redesign reset logic with sysreset features
- Use watchdog and gpio over DM
- Remove unused macros and fix some checkpatch issues
- Fix timer initialization not to be called twice
serial:
- zynq - Use platdata intead of priv data
sysreset:
- Add support for manual relocation in uclass
- Add gpio-restart driver
- Add microblaze soft reset driver
watchdog:
- Add support for aliases in uclass
- Add support for manual relocation in uclass
- Convert xilinx driver to DM
- cadence - update info in the driver and not stop wdt in probe
xilinx:
- Enable LED gpio for some targets with gpio-leds DT node
- Setup variables via Kconfig
zynq:
- Add support for watchdog aliases
- Add support for mini nand/nor configurations
- Wire FPGA initalization in SPL
zynqmp:
- Enable mass storage for zcu100
- Handle external pmufw files
- Add support for secure images
- Some Kconfig movements and alignments
- Add support for watchdog aliases
- Use subcommands style for platform command
- Add mmio_read/write platform commands
- DT updates
- Add support for mini qspi configuration
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/clk/clk_zynqmp.c | 6 | ||||
| -rw-r--r-- | drivers/fpga/zynqpl.c | 49 | ||||
| -rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpio/gpio-uclass.c | 35 | ||||
| -rw-r--r-- | drivers/gpio/xilinx_gpio.c | 265 | ||||
| -rw-r--r-- | drivers/gpio/zynq_gpio.c | 33 | ||||
| -rw-r--r-- | drivers/serial/serial_zynq.c | 32 | ||||
| -rw-r--r-- | drivers/sysreset/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/sysreset/Makefile | 2 | ||||
| -rw-r--r-- | drivers/sysreset/sysreset-uclass.c | 16 | ||||
| -rw-r--r-- | drivers/sysreset/sysreset_gpio.c | 59 | ||||
| -rw-r--r-- | drivers/sysreset/sysreset_microblaze.c | 30 | ||||
| -rw-r--r-- | drivers/watchdog/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/watchdog/cdns_wdt.c | 3 | ||||
| -rw-r--r-- | drivers/watchdog/wdt-uclass.c | 26 | ||||
| -rw-r--r-- | drivers/watchdog/xilinx_tb_wdt.c | 111 |
16 files changed, 612 insertions, 78 deletions
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c index a9e45007054..167f3f75a19 100644 --- a/drivers/clk/clk_zynqmp.c +++ b/drivers/clk/clk_zynqmp.c @@ -103,6 +103,8 @@ static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020; #define PLLCTRL_BYPASS_SHFT 3 #define PLLCTRL_POST_SRC_SHFT 24 #define PLLCTRL_POST_SRC_MASK (0x7 << PLLCTRL_POST_SRC_SHFT) +#define PLLCTRL_PRE_SRC_SHFT 20 +#define PLLCTRL_PRE_SRC_MASK (0x7 << PLLCTRL_PRE_SRC_SHFT) #define NUM_MIO_PINS 77 @@ -310,8 +312,8 @@ static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl, u32 src_sel; if (is_pre_src) - src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >> - PLLCTRL_POST_SRC_SHFT; + src_sel = (clk_ctrl & PLLCTRL_PRE_SRC_MASK) >> + PLLCTRL_PRE_SRC_SHFT; else src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >> PLLCTRL_POST_SRC_SHFT; diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index fd37d18c7f4..499310d0c0b 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -17,6 +17,7 @@ #define DEVCFG_CTRL_PCFG_PROG_B 0x40000000 #define DEVCFG_CTRL_PCFG_AES_EFUSE_MASK 0x00001000 +#define DEVCFG_CTRL_PCAP_RATE_EN_MASK 0x02000000 #define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040 #define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840 #define DEVCFG_ISR_RX_FIFO_OV 0x00040000 @@ -410,7 +411,7 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize, return FPGA_SUCCESS; } -#if defined(CONFIG_CMD_FPGA_LOADFS) +#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD) static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, fpga_fs_info *fsinfo) { @@ -493,7 +494,51 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, struct xilinx_fpga_op zynq_op = { .load = zynq_load, -#if defined(CONFIG_CMD_FPGA_LOADFS) +#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD) .loadfs = zynq_loadfs, #endif }; + +#ifdef CONFIG_CMD_ZYNQ_AES +/* + * Load the encrypted image from src addr and decrypt the image and + * place it back the decrypted image into dstaddr. + */ +int zynq_decrypt_load(u32 srcaddr, u32 srclen, u32 dstaddr, u32 dstlen) +{ + if (srcaddr < SZ_1M || dstaddr < SZ_1M) { + printf("%s: src and dst addr should be > 1M\n", + __func__); + return FPGA_FAIL; + } + + if (zynq_dma_xfer_init(BIT_NONE)) { + printf("%s: zynq_dma_xfer_init FAIL\n", __func__); + return FPGA_FAIL; + } + + writel((readl(&devcfg_base->ctrl) | DEVCFG_CTRL_PCAP_RATE_EN_MASK), + &devcfg_base->ctrl); + + debug("%s: Source = 0x%08X\n", __func__, (u32)srcaddr); + debug("%s: Size = %zu\n", __func__, srclen); + + /* flush(clean & invalidate) d-cache range buf */ + flush_dcache_range((u32)srcaddr, (u32)srcaddr + + roundup(srclen << 2, ARCH_DMA_MINALIGN)); + /* + * Flush destination address range only if image is not + * bitstream. + */ + flush_dcache_range((u32)dstaddr, (u32)dstaddr + + roundup(dstlen << 2, ARCH_DMA_MINALIGN)); + + if (zynq_dma_transfer(srcaddr | 1, srclen, dstaddr | 1, dstlen)) + return FPGA_FAIL; + + writel((readl(&devcfg_base->ctrl) & ~DEVCFG_CTRL_PCAP_RATE_EN_MASK), + &devcfg_base->ctrl); + + return FPGA_SUCCESS; +} +#endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 29af22ecc70..5699a71b231 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -185,6 +185,7 @@ config SANDBOX_GPIO_COUNT config XILINX_GPIO bool "Xilinx GPIO driver" + depends on DM_GPIO help This config enable the Xilinx GPIO driver for Microblaze. diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index e9d08e2ebc2..da5e9ba6e52 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -854,11 +854,46 @@ static int gpio_pre_remove(struct udevice *dev) return gpio_renumber(dev); } +static int gpio_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->request) + ops->request += gd->reloc_off; + if (ops->free) + ops->free += gd->reloc_off; + if (ops->direction_input) + ops->direction_input += gd->reloc_off; + if (ops->direction_output) + ops->direction_output += gd->reloc_off; + if (ops->get_value) + ops->get_value += gd->reloc_off; + if (ops->set_value) + ops->set_value += gd->reloc_off; + if (ops->get_open_drain) + ops->get_open_drain += gd->reloc_off; + if (ops->set_open_drain) + ops->set_open_drain += gd->reloc_off; + if (ops->get_function) + ops->get_function += gd->reloc_off; + if (ops->xlate) + ops->xlate += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + UCLASS_DRIVER(gpio) = { .id = UCLASS_GPIO, .name = "gpio", .flags = DM_UC_FLAG_SEQ_ALIAS, .post_probe = gpio_post_probe, + .post_bind = gpio_post_bind, .pre_remove = gpio_pre_remove, .per_device_auto_alloc_size = sizeof(struct gpio_dev_priv), }; diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c index 74c5be0865d..48b52c985a5 100644 --- a/drivers/gpio/xilinx_gpio.c +++ b/drivers/gpio/xilinx_gpio.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2013 Xilinx, Michal Simek + * Copyright (c) 2013 - 2018 Xilinx, Michal Simek */ #include <common.h> @@ -9,6 +9,7 @@ #include <linux/list.h> #include <asm/io.h> #include <asm/gpio.h> +#include <dm.h> static LIST_HEAD(gpio_list); @@ -23,6 +24,8 @@ struct gpio_regs { u32 gpiodir; }; +#if !defined(CONFIG_DM_GPIO) + #define GPIO_NAME_SIZE 10 struct gpio_names { @@ -345,3 +348,263 @@ int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0, u32 gpio_no1) /* Return the first gpio allocated for this device */ return ret; } +#else +#include <dt-bindings/gpio/gpio.h> + +#define XILINX_GPIO_MAX_BANK 2 + +struct xilinx_gpio_platdata { + struct gpio_regs *regs; + int bank_max[XILINX_GPIO_MAX_BANK]; + int bank_input[XILINX_GPIO_MAX_BANK]; + int bank_output[XILINX_GPIO_MAX_BANK]; +}; + +static int xilinx_gpio_get_bank_pin(unsigned offset, u32 *bank_num, + u32 *bank_pin_num, struct udevice *dev) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + u32 bank, max_pins; + /* the first gpio is 0 not 1 */ + u32 pin_num = offset; + + for (bank = 0; bank < XILINX_GPIO_MAX_BANK; bank++) { + max_pins = platdata->bank_max[bank]; + if (pin_num < max_pins) { + debug("%s: found at bank 0x%x pin 0x%x\n", __func__, + bank, pin_num); + *bank_num = bank; + *bank_pin_num = pin_num; + return 0; + } + pin_num -= max_pins; + } + + return -EINVAL; +} + +static int xilinx_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int val, ret; + u32 bank, pin; + + ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev); + if (ret) + return ret; + + debug("%s: regs: %lx, value: %x, gpio: %x, bank %x, pin %x\n", + __func__, (ulong)platdata->regs, value, offset, bank, pin); + + if (value) { + val = readl(&platdata->regs->gpiodata + bank * 2); + val = val | (1 << pin); + writel(val, &platdata->regs->gpiodata + bank * 2); + } else { + val = readl(&platdata->regs->gpiodata + bank * 2); + val = val & ~(1 << pin); + writel(val, &platdata->regs->gpiodata + bank * 2); + } + + return val; +}; + +static int xilinx_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int val, ret; + u32 bank, pin; + + ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev); + if (ret) + return ret; + + debug("%s: regs: %lx, gpio: %x, bank %x, pin %x\n", __func__, + (ulong)platdata->regs, offset, bank, pin); + + val = readl(&platdata->regs->gpiodata + bank * 2); + val = !!(val & (1 << pin)); + + return val; +}; + +static int xilinx_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int val, ret; + u32 bank, pin; + + /* Check if all pins are inputs */ + if (platdata->bank_input[bank]) + return GPIOF_INPUT; + + /* Check if all pins are outputs */ + if (platdata->bank_output[bank]) + return GPIOF_OUTPUT; + + ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev); + if (ret) + return ret; + + /* FIXME test on dual */ + val = readl(&platdata->regs->gpiodir + bank * 2); + val = !(val & (1 << pin)); + + /* input is 1 in reg but GPIOF_INPUT is 0 */ + /* output is 0 in reg but GPIOF_OUTPUT is 1 */ + + return val; +} + +static int xilinx_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int val, ret; + u32 bank, pin; + + ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev); + if (ret) + return ret; + + /* can't change it if all is input by default */ + if (platdata->bank_input[bank]) + return -EINVAL; + + if (!platdata->bank_output[bank]) { + val = readl(&platdata->regs->gpiodir + bank * 2); + val = val & ~(1 << pin); + writel(val, &platdata->regs->gpiodir + bank * 2); + } + + xilinx_gpio_set_value(dev, offset, value); + + return 0; +} + +static int xilinx_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int val, ret; + u32 bank, pin; + + ret = xilinx_gpio_get_bank_pin(offset, &bank, &pin, dev); + if (ret) + return ret; + + /* Already input */ + if (platdata->bank_input[bank]) + return 0; + + /* can't change it if all is output by default */ + if (platdata->bank_output[bank]) + return -EINVAL; + + val = readl(&platdata->regs->gpiodir + bank * 2); + val = val | (1 << pin); + writel(val, &platdata->regs->gpiodir + bank * 2); + + return 0; +} + +static int xilinx_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + + desc->offset = args->args[0]; + + debug("%s: argc: %x, [0]: %x, [1]: %x, [2]: %x\n", __func__, + args->args_count, args->args[0], args->args[1], args->args[2]); + + /* + * The second cell is channel offset: + * 0 is first channel, 8 is second channel + * + * U-Boot driver just combine channels together that's why simply + * add amount of pins in second channel if present. + */ + if (args->args[1]) { + if (!platdata->bank_max[1]) { + printf("%s: %s has no second channel\n", + __func__, dev->name); + return -EINVAL; + } + + desc->offset += platdata->bank_max[0]; + } + + /* The third cell is optional */ + if (args->args_count > 2) + desc->flags = (args->args[2] & + GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0); + + debug("%s: offset %x, flags %lx\n", + __func__, desc->offset, desc->flags); + return 0; +} + +static const struct dm_gpio_ops xilinx_gpio_ops = { + .direction_input = xilinx_gpio_direction_input, + .direction_output = xilinx_gpio_direction_output, + .get_value = xilinx_gpio_get_value, + .set_value = xilinx_gpio_set_value, + .get_function = xilinx_gpio_get_function, + .xlate = xilinx_gpio_xlate, +}; + +static int xilinx_gpio_probe(struct udevice *dev) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->bank_name = dev->name; + + uc_priv->gpio_count = platdata->bank_max[0] + platdata->bank_max[1]; + + return 0; +} + +static int xilinx_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct xilinx_gpio_platdata *platdata = dev_get_platdata(dev); + int is_dual; + + platdata->regs = (struct gpio_regs *)dev_read_addr(dev); + + platdata->bank_max[0] = dev_read_u32_default(dev, + "xlnx,gpio-width", 0); + platdata->bank_input[0] = dev_read_u32_default(dev, + "xlnx,all-inputs", 0); + platdata->bank_output[0] = dev_read_u32_default(dev, + "xlnx,all-outputs", 0); + + is_dual = dev_read_u32_default(dev, "xlnx,is-dual", 0); + if (is_dual) { + platdata->bank_max[1] = dev_read_u32_default(dev, + "xlnx,gpio2-width", 0); + platdata->bank_input[1] = dev_read_u32_default(dev, + "xlnx,all-inputs-2", 0); + platdata->bank_output[1] = dev_read_u32_default(dev, + "xlnx,all-outputs-2", 0); + } + + return 0; +} + +static const struct udevice_id xilinx_gpio_ids[] = { + { .compatible = "xlnx,xps-gpio-1.00.a",}, + { } +}; + +U_BOOT_DRIVER(xilinx_gpio) = { + .name = "xlnx_gpio", + .id = UCLASS_GPIO, + .ops = &xilinx_gpio_ops, + .of_match = xilinx_gpio_ids, + .ofdata_to_platdata = xilinx_gpio_ofdata_to_platdata, + .probe = xilinx_gpio_probe, + .platdata_auto_alloc_size = sizeof(struct xilinx_gpio_platdata), +}; +#endif diff --git a/drivers/gpio/zynq_gpio.c b/drivers/gpio/zynq_gpio.c index 8d84e3fc131..f793ee5754a 100644 --- a/drivers/gpio/zynq_gpio.c +++ b/drivers/gpio/zynq_gpio.c @@ -15,8 +15,6 @@ #include <dm.h> #include <fdtdec.h> -DECLARE_GLOBAL_DATA_PTR; - /* Maximum banks */ #define ZYNQ_GPIO_MAX_BANK 4 @@ -178,7 +176,7 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num, } if (bank >= priv->p_data->max_bank) { - printf("Inavlid bank and pin num\n"); + printf("Invalid bank and pin num\n"); *bank_num = 0; *bank_pin_num = 0; } @@ -334,35 +332,12 @@ static const struct udevice_id zynq_gpio_ids[] = { { } }; -static void zynq_gpio_getplat_data(struct udevice *dev) -{ - const struct udevice_id *of_match = zynq_gpio_ids; - int ret; - struct zynq_gpio_privdata *priv = dev_get_priv(dev); - - while (of_match->compatible) { - ret = fdt_node_offset_by_compatible(gd->fdt_blob, -1, - of_match->compatible); - if (ret >= 0) { - priv->p_data = - (struct zynq_platform_data *)of_match->data; - break; - } else { - of_match++; - continue; - } - } - - if (!priv->p_data) - printf("No Platform data found\n"); -} - static int zynq_gpio_probe(struct udevice *dev) { struct zynq_gpio_privdata *priv = dev_get_priv(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - zynq_gpio_getplat_data(dev); + uc_priv->bank_name = dev->name; if (priv->p_data) uc_priv->gpio_count = priv->p_data->ngpio; @@ -374,7 +349,9 @@ static int zynq_gpio_ofdata_to_platdata(struct udevice *dev) { struct zynq_gpio_privdata *priv = dev_get_priv(dev); - priv->base = devfdt_get_addr(dev); + priv->base = (phys_addr_t)dev_read_addr(dev); + + priv->p_data = (struct zynq_platform_data *)dev_get_driver_data(dev); return 0; } diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index a191772ff04..f689015b4ae 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -39,7 +39,7 @@ struct uart_zynq { u32 baud_rate_divider; /* 0x34 - Baud Rate Divider [7:0] */ }; -struct zynq_uart_priv { +struct zynq_uart_platdata { struct uart_zynq *regs; }; @@ -105,7 +105,7 @@ static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c) static int zynq_serial_setbrg(struct udevice *dev, int baudrate) { - struct zynq_uart_priv *priv = dev_get_priv(dev); + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); unsigned long clock; int ret; @@ -130,28 +130,28 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate) return ret; } - _uart_zynq_serial_setbrg(priv->regs, clock, baudrate); + _uart_zynq_serial_setbrg(platdata->regs, clock, baudrate); return 0; } static int zynq_serial_probe(struct udevice *dev) { - struct zynq_uart_priv *priv = dev_get_priv(dev); + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); /* No need to reinitialize the UART after relocation */ if (gd->flags & GD_FLG_RELOC) return 0; - _uart_zynq_serial_init(priv->regs); + _uart_zynq_serial_init(platdata->regs); return 0; } static int zynq_serial_getc(struct udevice *dev) { - struct zynq_uart_priv *priv = dev_get_priv(dev); - struct uart_zynq *regs = priv->regs; + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); + struct uart_zynq *regs = platdata->regs; if (readl(®s->channel_sts) & ZYNQ_UART_SR_RXEMPTY) return -EAGAIN; @@ -161,15 +161,15 @@ static int zynq_serial_getc(struct udevice *dev) static int zynq_serial_putc(struct udevice *dev, const char ch) { - struct zynq_uart_priv *priv = dev_get_priv(dev); + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); - return _uart_zynq_serial_putc(priv->regs, ch); + return _uart_zynq_serial_putc(platdata->regs, ch); } static int zynq_serial_pending(struct udevice *dev, bool input) { - struct zynq_uart_priv *priv = dev_get_priv(dev); - struct uart_zynq *regs = priv->regs; + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); + struct uart_zynq *regs = platdata->regs; if (input) return !(readl(®s->channel_sts) & ZYNQ_UART_SR_RXEMPTY); @@ -179,11 +179,11 @@ static int zynq_serial_pending(struct udevice *dev, bool input) static int zynq_serial_ofdata_to_platdata(struct udevice *dev) { - struct zynq_uart_priv *priv = dev_get_priv(dev); + struct zynq_uart_platdata *platdata = dev_get_platdata(dev); - priv->regs = (struct uart_zynq *)dev_read_addr(dev); - if (IS_ERR(priv->regs)) - return PTR_ERR(priv->regs); + platdata->regs = (struct uart_zynq *)dev_read_addr(dev); + if (IS_ERR(platdata->regs)) + return PTR_ERR(platdata->regs); return 0; } @@ -207,7 +207,7 @@ U_BOOT_DRIVER(serial_zynq) = { .id = UCLASS_SERIAL, .of_match = zynq_serial_ids, .ofdata_to_platdata = zynq_serial_ofdata_to_platdata, - .priv_auto_alloc_size = sizeof(struct zynq_uart_priv), + .platdata_auto_alloc_size = sizeof(struct zynq_uart_platdata), .probe = zynq_serial_probe, .ops = &zynq_serial_ops, .flags = DM_FLAG_PRE_RELOC, diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index a6d48e8a662..f2524c18b7b 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -15,6 +15,20 @@ config SYSRESET if SYSRESET +config SYSRESET_GPIO + bool "Enable support for GPIO reset driver" + select GPIO + help + Reset support via GPIO pin connected reset logic. This is used for + example on Microblaze where reset logic can be controlled via GPIO + pin which triggers cpu reset. + +config SYSRESET_MICROBLAZE + bool "Enable support for Microblaze soft reset" + depends on MICROBLAZE + help + This is soft reset on Microblaze which does jump to 0x0 address. + config SYSRESET_PSCI bool "Enable support for PSCI System Reset" depends on ARM_PSCI_FW diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index 0da58a1cf6a..223a0716f0a 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -3,6 +3,8 @@ # (C) Copyright 2016 Cadence Design Systems Inc. obj-$(CONFIG_SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o +obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 7e06c3c90a7..840eab6b570 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -74,7 +74,23 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 0; } +static int sysreset_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct sysreset_ops *ops = sysreset_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->request) + ops->request += gd->reloc_off; + reloc_done++; + } +#endif + return 0; +} + UCLASS_DRIVER(sysreset) = { .id = UCLASS_SYSRESET, .name = "sysreset", + .post_bind = sysreset_post_bind, }; diff --git a/drivers/sysreset/sysreset_gpio.c b/drivers/sysreset/sysreset_gpio.c new file mode 100644 index 00000000000..ed9a49ad08c --- /dev/null +++ b/drivers/sysreset/sysreset_gpio.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Xilinx, Inc. - Michal Simek + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <asm/gpio.h> + +struct gpio_reboot_priv { + struct gpio_desc gpio; +}; + +static int gpio_reboot_request(struct udevice *dev, enum sysreset_t type) +{ + struct gpio_reboot_priv *priv = dev_get_priv(dev); + + /* + * When debug log is enabled please make sure that chars won't end up + * in output fifo. Or you can append udelay(); to get enough time + * to HW to emit output fifo. + */ + debug("GPIO reset\n"); + + /* Writing 1 respects polarity (active high/low) based on gpio->flags */ + return dm_gpio_set_value(&priv->gpio, 1); +} + +static struct sysreset_ops gpio_reboot_ops = { + .request = gpio_reboot_request, +}; + +int gpio_reboot_probe(struct udevice *dev) +{ + struct gpio_reboot_priv *priv = dev_get_priv(dev); + + /* + * Linux kernel DT binding contain others optional properties + * which are not supported now + */ + + return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); +} + +static const struct udevice_id led_gpio_ids[] = { + { .compatible = "gpio-restart" }, + { } +}; + +U_BOOT_DRIVER(gpio_reboot) = { + .id = UCLASS_SYSRESET, + .name = "gpio_restart", + .of_match = led_gpio_ids, + .ops = &gpio_reboot_ops, + .priv_auto_alloc_size = sizeof(struct gpio_reboot_priv), + .probe = gpio_reboot_probe, +}; diff --git a/drivers/sysreset/sysreset_microblaze.c b/drivers/sysreset/sysreset_microblaze.c new file mode 100644 index 00000000000..514c95817f2 --- /dev/null +++ b/drivers/sysreset/sysreset_microblaze.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Xilinx, Inc. - Michal Simek + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <sysreset.h> +#include <linux/err.h> + +static int microblaze_sysreset_request(struct udevice *dev, + enum sysreset_t type) +{ + puts("Microblaze soft reset sysreset\n"); + __asm__ __volatile__ (" mts rmsr, r0;" \ + "bra r0"); + + return -EINPROGRESS; +} + +static struct sysreset_ops microblaze_sysreset = { + .request = microblaze_sysreset_request, +}; + +U_BOOT_DRIVER(sysreset_microblaze) = { + .id = UCLASS_SYSRESET, + .name = "mb_soft_reset", + .ops = µblaze_sysreset, +}; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 148c6a0d687..d545b3e0007 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -103,4 +103,12 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. +config XILINX_TB_WATCHDOG + bool "Xilinx Axi watchdog timer support" + depends on WDT + imply WATCHDOG + help + Select this to enable Xilinx Axi watchdog timer, which can be found on some + Xilinx Microblaze Platforms. + endmenu diff --git a/drivers/watchdog/cdns_wdt.c b/drivers/watchdog/cdns_wdt.c index f7618f86da1..fc85fbcec25 100644 --- a/drivers/watchdog/cdns_wdt.c +++ b/drivers/watchdog/cdns_wdt.c @@ -224,8 +224,6 @@ static int cdns_wdt_probe(struct udevice *dev) { debug("%s: Probing wdt%u\n", __func__, dev->seq); - cdns_wdt_stop(dev); - return 0; } @@ -251,6 +249,7 @@ static const struct wdt_ops cdns_wdt_ops = { .start = cdns_wdt_start, .reset = cdns_wdt_reset, .stop = cdns_wdt_stop, + /* There is no bit/reg/support in IP for expire_now functionality */ }; static const struct udevice_id cdns_wdt_ids[] = { diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c index 4a619f71fe9..23b7e3360d3 100644 --- a/drivers/watchdog/wdt-uclass.c +++ b/drivers/watchdog/wdt-uclass.c @@ -63,7 +63,31 @@ int wdt_expire_now(struct udevice *dev, ulong flags) return ret; } +static int wdt_post_bind(struct udevice *dev) +{ +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + struct wdt_ops *ops = (struct wdt_ops *)device_get_ops(dev); + static int reloc_done; + + if (!reloc_done) { + if (ops->start) + ops->start += gd->reloc_off; + if (ops->stop) + ops->stop += gd->reloc_off; + if (ops->reset) + ops->reset += gd->reloc_off; + if (ops->expire_now) + ops->expire_now += gd->reloc_off; + + reloc_done++; + } +#endif + return 0; +} + UCLASS_DRIVER(wdt) = { .id = UCLASS_WDT, - .name = "wdt", + .name = "watchdog", + .flags = DM_UC_FLAG_SEQ_ALIAS, + .post_bind = wdt_post_bind, }; diff --git a/drivers/watchdog/xilinx_tb_wdt.c b/drivers/watchdog/xilinx_tb_wdt.c index 2274123e491..929c8e60d37 100644 --- a/drivers/watchdog/xilinx_tb_wdt.c +++ b/drivers/watchdog/xilinx_tb_wdt.c @@ -1,13 +1,17 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2011-2013 Xilinx Inc. + * Xilinx AXI platforms watchdog timer driver. + * + * Author(s): Michal Simek <[email protected]> + * Shreenidhi Shedi <[email protected]> + * + * Copyright (c) 2011-2018 Xilinx Inc. */ #include <common.h> -#include <asm/io.h> -#include <asm/microblaze_intc.h> -#include <asm/processor.h> -#include <watchdog.h> +#include <dm.h> +#include <wdt.h> +#include <linux/io.h> #define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status Mask */ #define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state Mask */ @@ -20,49 +24,104 @@ struct watchdog_regs { u32 tbr; /* 0x8 */ }; -static struct watchdog_regs *watchdog_base = - (struct watchdog_regs *)CONFIG_WATCHDOG_BASEADDR; +struct xlnx_wdt_platdata { + bool enable_once; + struct watchdog_regs *regs; +}; -void hw_watchdog_reset(void) +static int xlnx_wdt_reset(struct udevice *dev) { u32 reg; + struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev); + + debug("%s ", __func__); /* Read the current contents of TCSR0 */ - reg = readl(&watchdog_base->twcsr0); + reg = readl(&platdata->regs->twcsr0); /* Clear the watchdog WDS bit */ if (reg & (XWT_CSR0_EWDT1_MASK | XWT_CSRX_EWDT2_MASK)) - writel(reg | XWT_CSR0_WDS_MASK, &watchdog_base->twcsr0); + writel(reg | XWT_CSR0_WDS_MASK, &platdata->regs->twcsr0); + + return 0; } -void hw_watchdog_disable(void) +static int xlnx_wdt_stop(struct udevice *dev) { u32 reg; + struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev); + + if (platdata->enable_once) { + debug("Can't stop Xilinx watchdog.\n"); + return -EBUSY; + } /* Read the current contents of TCSR0 */ - reg = readl(&watchdog_base->twcsr0); + reg = readl(&platdata->regs->twcsr0); + + writel(reg & ~XWT_CSR0_EWDT1_MASK, &platdata->regs->twcsr0); + writel(~XWT_CSRX_EWDT2_MASK, &platdata->regs->twcsr1); - writel(reg & ~XWT_CSR0_EWDT1_MASK, &watchdog_base->twcsr0); - writel(~XWT_CSRX_EWDT2_MASK, &watchdog_base->twcsr1); + debug("Watchdog disabled!\n"); - puts("Watchdog disabled!\n"); + return 0; } -static void hw_watchdog_isr(void *arg) +static int xlnx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) { - hw_watchdog_reset(); + struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev); + + debug("%s:\n", __func__); + + writel((XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK | XWT_CSR0_EWDT1_MASK), + &platdata->regs->twcsr0); + + writel(XWT_CSRX_EWDT2_MASK, &platdata->regs->twcsr1); + + return 0; } -void hw_watchdog_init(void) +static int xlnx_wdt_probe(struct udevice *dev) { - int ret; + debug("%s: Probing wdt%u\n", __func__, dev->seq); - writel((XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK | XWT_CSR0_EWDT1_MASK), - &watchdog_base->twcsr0); - writel(XWT_CSRX_EWDT2_MASK, &watchdog_base->twcsr1); + return 0; +} - ret = install_interrupt_handler(CONFIG_WATCHDOG_IRQ, - hw_watchdog_isr, NULL); - if (ret) - puts("Watchdog IRQ registration failed."); +static int xlnx_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct xlnx_wdt_platdata *platdata = dev_get_platdata(dev); + + platdata->regs = (struct watchdog_regs *)dev_read_addr(dev); + if (IS_ERR(platdata->regs)) + return PTR_ERR(platdata->regs); + + platdata->enable_once = dev_read_u32_default(dev, + "xlnx,wdt-enable-once", 0); + + debug("%s: wdt-enable-once %d\n", __func__, platdata->enable_once); + + return 0; } + +static const struct wdt_ops xlnx_wdt_ops = { + .start = xlnx_wdt_start, + .reset = xlnx_wdt_reset, + .stop = xlnx_wdt_stop, +}; + +static const struct udevice_id xlnx_wdt_ids[] = { + { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, + { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, + {}, +}; + +U_BOOT_DRIVER(xlnx_wdt) = { + .name = "xlnx_wdt", + .id = UCLASS_WDT, + .of_match = xlnx_wdt_ids, + .probe = xlnx_wdt_probe, + .platdata_auto_alloc_size = sizeof(struct xlnx_wdt_platdata), + .ofdata_to_platdata = xlnx_wdt_ofdata_to_platdata, + .ops = &xlnx_wdt_ops, +}; |
