diff --git a/Documentation/devicetree/bindings/clock/ti-keystone-pllctrl.txt b/Documentation/devicetree/bindings/clock/ti-keystone-pllctrl.txt new file mode 100644 index 000000000000..3e6a81e99804 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti-keystone-pllctrl.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments keystone pll controller + +The main pll controller used to drive theC66x CorePacs, the switch fabric, +and a majority of the peripheral clocks (all but the ARM CorePacs, DDR3 and +the NETCP modules) requires a PLL Controller to manage the various clock +divisions, gating, and synchronization. + +Required properties: + +- compatible: "ti,keystone-pllctrl", "syscon" + +- reg: contains offset/length value for pll controller + registers space. + +Example: + +pllctrl: pll-controller@0x02310000 { + compatible = "ti,keystone-pllctrl", "syscon"; + reg = <0x02310000 0x200>; +}; diff --git a/Documentation/devicetree/bindings/power/reset/keystone-reset.txt b/Documentation/devicetree/bindings/power/reset/keystone-reset.txt new file mode 100644 index 000000000000..c82f12e2d85c --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/keystone-reset.txt @@ -0,0 +1,67 @@ +* Device tree bindings for Texas Instruments keystone reset + +This node is intended to allow SoC reset in case of software reset +of selected watchdogs. + +The Keystone SoCs can contain up to 4 watchdog timers to reset +SoC. Each watchdog timer event input is connected to the Reset Mux +block. The Reset Mux block can be configured to cause reset or not. + +Additionally soft or hard reset can be configured. + +Required properties: + +- compatible: ti,keystone-reset + +- ti,syscon-pll: phandle/offset pair. The phandle to syscon used to + access pll controller registers and the offset to use + reset control registers. + +- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to + access device state control registers and the offset + in order to use mux block registers for all watchdogs. + +Optional properties: + +- ti,soft-reset: Boolean option indicating soft reset. + By default hard reset is used. + +- ti,wdt-list: WDT list that can cause SoC reset. It's not related + to WDT driver, it's just needed to enable a SoC related + reset that's triggered by one of WDTs. The list is + in format: <0>, <2>; It can be in random order and + begins from 0 to 3, as keystone can contain up to 4 SoC + reset watchdogs and can be in random order. + +Example 1: +Setup keystone reset so that in case software reset or +WDT0 is triggered it issues hard reset for SoC. + +pllctrl: pll-controller@02310000 { + compatible = "ti,keystone-pllctrl", "syscon"; + reg = <0x02310000 0x200>; +}; + +devctrl: device-state-control@02620000 { + compatible = "ti,keystone-devctrl", "syscon"; + reg = <0x02620000 0x1000>; +}; + +rstctrl: reset-controller { + compatible = "ti,keystone-reset"; + ti,syscon-pll = <&pllctrl 0xe4>; + ti,syscon-dev = <&devctrl 0x328>; + ti,wdt-list = <0>; +}; + +Example 2: +Setup keystone reset so that in case of software reset or +WDT0 or WDT2 is triggered it issues soft reset for SoC. + +rstctrl: reset-controller { + compatible = "ti,keystone-reset"; + ti,syscon-pll = <&pllctrl 0xe4>; + ti,syscon-dev = <&devctrl 0x328>; + ti,wdt-list = <0>, <2>; + ti,soft-reset; +}; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 67aeb6ec08f9..736b91994249 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -64,3 +64,11 @@ config POWER_RESET_XGENE depends on POWER_RESET help Reboot support for the APM SoC X-Gene Eval boards. + +config POWER_RESET_KEYSTONE + bool "Keystone reset driver" + depends on ARCH_KEYSTONE + select MFD_SYSCON + help + Reboot support for the KEYSTONE SoCs. + diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 950fdc011c7a..618541b70207 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o +obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c new file mode 100644 index 000000000000..408a18fd91cb --- /dev/null +++ b/drivers/power/reset/keystone-reset.c @@ -0,0 +1,166 @@ +/* + * TI keystone reboot driver + * + * Copyright (C) 2014 Texas Instruments Incorporated. http://www.ti.com/ + * + * Author: Ivan Khoronzhuk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RSTYPE_RG 0x0 +#define RSCTRL_RG 0x4 +#define RSCFG_RG 0x8 +#define RSISO_RG 0xc + +#define RSCTRL_KEY_MASK 0x0000ffff +#define RSCTRL_RESET_MASK BIT(16) +#define RSCTRL_KEY 0x5a69 + +#define RSMUX_OMODE_MASK 0xe +#define RSMUX_OMODE_RESET_ON 0xa +#define RSMUX_OMODE_RESET_OFF 0x0 +#define RSMUX_LOCK_MASK 0x1 +#define RSMUX_LOCK_SET 0x1 + +#define RSCFG_RSTYPE_SOFT 0x300f +#define RSCFG_RSTYPE_HARD 0x0 + +#define WDT_MUX_NUMBER 0x4 + +static int rspll_offset; +static struct regmap *pllctrl_regs; + +/** + * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG + * To be able to access to RSCTRL, RSCFG registers + * we have to write a key before + */ +static inline int rsctrl_enable_rspll_write(void) +{ + return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG, + RSCTRL_KEY_MASK, RSCTRL_KEY); +} + +static void rsctrl_restart(enum reboot_mode mode, const char *cmd) +{ + /* enable write access to RSTCTRL */ + rsctrl_enable_rspll_write(); + + /* reset the SOC */ + regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG, + RSCTRL_RESET_MASK, 0); +} + +static struct of_device_id rsctrl_of_match[] = { + {.compatible = "ti,keystone-reset", }, + {}, +}; + +static int rsctrl_probe(struct platform_device *pdev) +{ + int i; + int ret; + u32 val; + unsigned int rg; + u32 rsmux_offset; + struct regmap *devctrl_regs; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + if (!np) + return -ENODEV; + + /* get regmaps */ + pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll"); + if (IS_ERR(pllctrl_regs)) + return PTR_ERR(pllctrl_regs); + + devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev"); + if (IS_ERR(devctrl_regs)) + return PTR_ERR(devctrl_regs); + + ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset); + if (ret) { + dev_err(dev, "couldn't read the reset pll offset!\n"); + return -EINVAL; + } + + ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset); + if (ret) { + dev_err(dev, "couldn't read the rsmux offset!\n"); + return -EINVAL; + } + + /* set soft/hard reset */ + val = of_property_read_bool(np, "ti,soft-reset"); + val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD; + + ret = rsctrl_enable_rspll_write(); + if (ret) + return ret; + + ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val); + if (ret) + return ret; + + arm_pm_restart = rsctrl_restart; + + /* disable a reset isolation for all module clocks */ + ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0); + if (ret) + return ret; + + /* enable a reset for watchdogs from wdt-list */ + for (i = 0; i < WDT_MUX_NUMBER; i++) { + ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val); + if (ret == -EOVERFLOW && !i) { + dev_err(dev, "ti,wdt-list property has to contain at" + "least one entry\n"); + return -EINVAL; + } else if (ret) { + break; + } + + if (val >= WDT_MUX_NUMBER) { + dev_err(dev, "ti,wdt-list property can contain" + "only numbers < 4\n"); + return -EINVAL; + } + + rg = rsmux_offset + val * 4; + + ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK, + RSMUX_OMODE_RESET_ON | + RSMUX_LOCK_SET); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver rsctrl_driver = { + .probe = rsctrl_probe, + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .of_match_table = rsctrl_of_match, + }, +}; +module_platform_driver(rsctrl_driver); + +MODULE_AUTHOR("Ivan Khoronzhuk "); +MODULE_DESCRIPTION("Texas Instruments keystone reset driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" KBUILD_MODNAME);