162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Atmel AT91 SAM9 & SAMA5 SoCs reset code 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007 Atmel Corporation. 562306a36Sopenharmony_ci * Copyright (C) BitBox Ltd 2010 662306a36Sopenharmony_ci * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com> 762306a36Sopenharmony_ci * Copyright (C) 2014 Free Electrons 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 1062306a36Sopenharmony_ci * License version 2. This program is licensed "as is" without any 1162306a36Sopenharmony_ci * warranty of any kind, whether express or implied. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/clk.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/of_address.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/reboot.h> 2062306a36Sopenharmony_ci#include <linux/reset-controller.h> 2162306a36Sopenharmony_ci#include <linux/power/power_on_reason.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <soc/at91/at91sam9_ddrsdr.h> 2462306a36Sopenharmony_ci#include <soc/at91/at91sam9_sdramc.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <dt-bindings/reset/sama7g5-reset.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */ 2962306a36Sopenharmony_ci#define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */ 3062306a36Sopenharmony_ci#define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */ 3162306a36Sopenharmony_ci#define AT91_RSTC_EXTRST BIT(3) /* External Reset */ 3262306a36Sopenharmony_ci#define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */ 3562306a36Sopenharmony_ci#define AT91_RSTC_URSTS BIT(0) /* User Reset Status */ 3662306a36Sopenharmony_ci#define AT91_RSTC_RSTTYP GENMASK(10, 8) /* Reset Type */ 3762306a36Sopenharmony_ci#define AT91_RSTC_NRSTL BIT(16) /* NRST Pin Level */ 3862306a36Sopenharmony_ci#define AT91_RSTC_SRCMP BIT(17) /* Software Reset Command in Progress */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */ 4162306a36Sopenharmony_ci#define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */ 4262306a36Sopenharmony_ci#define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */ 4362306a36Sopenharmony_ci#define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */ 4462306a36Sopenharmony_ci#define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/** 4762306a36Sopenharmony_ci * enum reset_type - reset types 4862306a36Sopenharmony_ci * @RESET_TYPE_GENERAL: first power-up reset 4962306a36Sopenharmony_ci * @RESET_TYPE_WAKEUP: return from backup mode 5062306a36Sopenharmony_ci * @RESET_TYPE_WATCHDOG: watchdog fault 5162306a36Sopenharmony_ci * @RESET_TYPE_SOFTWARE: processor reset required by software 5262306a36Sopenharmony_ci * @RESET_TYPE_USER: NRST pin detected low 5362306a36Sopenharmony_ci * @RESET_TYPE_CPU_FAIL: CPU clock failure detection 5462306a36Sopenharmony_ci * @RESET_TYPE_XTAL_FAIL: 32KHz crystal failure dectection fault 5562306a36Sopenharmony_ci * @RESET_TYPE_ULP2: ULP2 reset 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cienum reset_type { 5862306a36Sopenharmony_ci RESET_TYPE_GENERAL = 0, 5962306a36Sopenharmony_ci RESET_TYPE_WAKEUP = 1, 6062306a36Sopenharmony_ci RESET_TYPE_WATCHDOG = 2, 6162306a36Sopenharmony_ci RESET_TYPE_SOFTWARE = 3, 6262306a36Sopenharmony_ci RESET_TYPE_USER = 4, 6362306a36Sopenharmony_ci RESET_TYPE_CPU_FAIL = 6, 6462306a36Sopenharmony_ci RESET_TYPE_XTAL_FAIL = 7, 6562306a36Sopenharmony_ci RESET_TYPE_ULP2 = 8, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/** 6962306a36Sopenharmony_ci * struct at91_reset - AT91 reset specific data structure 7062306a36Sopenharmony_ci * @rstc_base: base address for system reset 7162306a36Sopenharmony_ci * @ramc_base: array with base addresses of RAM controllers 7262306a36Sopenharmony_ci * @dev_base: base address for devices reset 7362306a36Sopenharmony_ci * @sclk: slow clock 7462306a36Sopenharmony_ci * @data: platform specific reset data 7562306a36Sopenharmony_ci * @rcdev: reset controller device 7662306a36Sopenharmony_ci * @lock: lock for devices reset register access 7762306a36Sopenharmony_ci * @nb: reset notifier block 7862306a36Sopenharmony_ci * @args: SoC specific system reset arguments 7962306a36Sopenharmony_ci * @ramc_lpr: SDRAM Controller Low Power Register 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_cistruct at91_reset { 8262306a36Sopenharmony_ci void __iomem *rstc_base; 8362306a36Sopenharmony_ci void __iomem *ramc_base[2]; 8462306a36Sopenharmony_ci void __iomem *dev_base; 8562306a36Sopenharmony_ci struct clk *sclk; 8662306a36Sopenharmony_ci const struct at91_reset_data *data; 8762306a36Sopenharmony_ci struct reset_controller_dev rcdev; 8862306a36Sopenharmony_ci spinlock_t lock; 8962306a36Sopenharmony_ci struct notifier_block nb; 9062306a36Sopenharmony_ci u32 args; 9162306a36Sopenharmony_ci u32 ramc_lpr; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define to_at91_reset(r) container_of(r, struct at91_reset, rcdev) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/** 9762306a36Sopenharmony_ci * struct at91_reset_data - AT91 reset data 9862306a36Sopenharmony_ci * @reset_args: SoC specific system reset arguments 9962306a36Sopenharmony_ci * @n_device_reset: number of device resets 10062306a36Sopenharmony_ci * @device_reset_min_id: min id for device reset 10162306a36Sopenharmony_ci * @device_reset_max_id: max id for device reset 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistruct at91_reset_data { 10462306a36Sopenharmony_ci u32 reset_args; 10562306a36Sopenharmony_ci u32 n_device_reset; 10662306a36Sopenharmony_ci u8 device_reset_min_id; 10762306a36Sopenharmony_ci u8 device_reset_max_id; 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci* unless the SDRAM is cleanly shutdown before we hit the 11262306a36Sopenharmony_ci* reset register it can be left driving the data bus and 11362306a36Sopenharmony_ci* killing the chance of a subsequent boot from NAND 11462306a36Sopenharmony_ci*/ 11562306a36Sopenharmony_cistatic int at91_reset(struct notifier_block *this, unsigned long mode, 11662306a36Sopenharmony_ci void *cmd) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct at91_reset *reset = container_of(this, struct at91_reset, nb); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci asm volatile( 12162306a36Sopenharmony_ci /* Align to cache lines */ 12262306a36Sopenharmony_ci ".balign 32\n\t" 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Disable SDRAM0 accesses */ 12562306a36Sopenharmony_ci " tst %0, #0\n\t" 12662306a36Sopenharmony_ci " beq 1f\n\t" 12762306a36Sopenharmony_ci " str %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" 12862306a36Sopenharmony_ci /* Power down SDRAM0 */ 12962306a36Sopenharmony_ci " str %4, [%0, %6]\n\t" 13062306a36Sopenharmony_ci /* Disable SDRAM1 accesses */ 13162306a36Sopenharmony_ci "1: tst %1, #0\n\t" 13262306a36Sopenharmony_ci " beq 2f\n\t" 13362306a36Sopenharmony_ci " strne %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t" 13462306a36Sopenharmony_ci /* Power down SDRAM1 */ 13562306a36Sopenharmony_ci " strne %4, [%1, %6]\n\t" 13662306a36Sopenharmony_ci /* Reset CPU */ 13762306a36Sopenharmony_ci "2: str %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t" 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci " b .\n\t" 14062306a36Sopenharmony_ci : 14162306a36Sopenharmony_ci : "r" (reset->ramc_base[0]), 14262306a36Sopenharmony_ci "r" (reset->ramc_base[1]), 14362306a36Sopenharmony_ci "r" (reset->rstc_base), 14462306a36Sopenharmony_ci "r" (1), 14562306a36Sopenharmony_ci "r" cpu_to_le32(AT91_DDRSDRC_LPCB_POWER_DOWN), 14662306a36Sopenharmony_ci "r" (reset->data->reset_args), 14762306a36Sopenharmony_ci "r" (reset->ramc_lpr) 14862306a36Sopenharmony_ci : "r4"); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return NOTIFY_DONE; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic const char *at91_reset_reason(struct at91_reset *reset) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); 15662306a36Sopenharmony_ci const char *reason; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci switch ((reg & AT91_RSTC_RSTTYP) >> 8) { 15962306a36Sopenharmony_ci case RESET_TYPE_GENERAL: 16062306a36Sopenharmony_ci reason = POWER_ON_REASON_REGULAR; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci case RESET_TYPE_WAKEUP: 16362306a36Sopenharmony_ci reason = POWER_ON_REASON_RTC; 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case RESET_TYPE_WATCHDOG: 16662306a36Sopenharmony_ci reason = POWER_ON_REASON_WATCHDOG; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci case RESET_TYPE_SOFTWARE: 16962306a36Sopenharmony_ci reason = POWER_ON_REASON_SOFTWARE; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci case RESET_TYPE_USER: 17262306a36Sopenharmony_ci reason = POWER_ON_REASON_RST_BTN; 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci case RESET_TYPE_CPU_FAIL: 17562306a36Sopenharmony_ci reason = POWER_ON_REASON_CPU_CLK_FAIL; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case RESET_TYPE_XTAL_FAIL: 17862306a36Sopenharmony_ci reason = POWER_ON_REASON_XTAL_FAIL; 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci case RESET_TYPE_ULP2: 18162306a36Sopenharmony_ci reason = POWER_ON_REASON_BROWN_OUT; 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci default: 18462306a36Sopenharmony_ci reason = POWER_ON_REASON_UNKNOWN; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return reason; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic ssize_t power_on_reason_show(struct device *dev, 19262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 19562306a36Sopenharmony_ci struct at91_reset *reset = platform_get_drvdata(pdev); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return sprintf(buf, "%s\n", at91_reset_reason(reset)); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(power_on_reason); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic const struct of_device_id at91_ramc_of_match[] = { 20262306a36Sopenharmony_ci { 20362306a36Sopenharmony_ci .compatible = "atmel,at91sam9260-sdramc", 20462306a36Sopenharmony_ci .data = (void *)AT91_SDRAMC_LPR, 20562306a36Sopenharmony_ci }, 20662306a36Sopenharmony_ci { 20762306a36Sopenharmony_ci .compatible = "atmel,at91sam9g45-ddramc", 20862306a36Sopenharmony_ci .data = (void *)AT91_DDRSDRC_LPR, 20962306a36Sopenharmony_ci }, 21062306a36Sopenharmony_ci { /* sentinel */ } 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const struct at91_reset_data sam9260 = { 21462306a36Sopenharmony_ci .reset_args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST, 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic const struct at91_reset_data samx7 = { 21862306a36Sopenharmony_ci .reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const struct at91_reset_data sama7g5 = { 22262306a36Sopenharmony_ci .reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST, 22362306a36Sopenharmony_ci .n_device_reset = 3, 22462306a36Sopenharmony_ci .device_reset_min_id = SAMA7G5_RESET_USB_PHY1, 22562306a36Sopenharmony_ci .device_reset_max_id = SAMA7G5_RESET_USB_PHY3, 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const struct of_device_id at91_reset_of_match[] = { 22962306a36Sopenharmony_ci { 23062306a36Sopenharmony_ci .compatible = "atmel,at91sam9260-rstc", 23162306a36Sopenharmony_ci .data = &sam9260, 23262306a36Sopenharmony_ci }, 23362306a36Sopenharmony_ci { 23462306a36Sopenharmony_ci .compatible = "atmel,at91sam9g45-rstc", 23562306a36Sopenharmony_ci .data = &sam9260, 23662306a36Sopenharmony_ci }, 23762306a36Sopenharmony_ci { 23862306a36Sopenharmony_ci .compatible = "atmel,sama5d3-rstc", 23962306a36Sopenharmony_ci .data = &sam9260, 24062306a36Sopenharmony_ci }, 24162306a36Sopenharmony_ci { 24262306a36Sopenharmony_ci .compatible = "atmel,samx7-rstc", 24362306a36Sopenharmony_ci .data = &samx7, 24462306a36Sopenharmony_ci }, 24562306a36Sopenharmony_ci { 24662306a36Sopenharmony_ci .compatible = "microchip,sam9x60-rstc", 24762306a36Sopenharmony_ci .data = &samx7, 24862306a36Sopenharmony_ci }, 24962306a36Sopenharmony_ci { 25062306a36Sopenharmony_ci .compatible = "microchip,sama7g5-rstc", 25162306a36Sopenharmony_ci .data = &sama7g5, 25262306a36Sopenharmony_ci }, 25362306a36Sopenharmony_ci { /* sentinel */ } 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, at91_reset_of_match); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int at91_reset_update(struct reset_controller_dev *rcdev, 25862306a36Sopenharmony_ci unsigned long id, bool assert) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct at91_reset *reset = to_at91_reset(rcdev); 26162306a36Sopenharmony_ci unsigned long flags; 26262306a36Sopenharmony_ci u32 val; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci spin_lock_irqsave(&reset->lock, flags); 26562306a36Sopenharmony_ci val = readl_relaxed(reset->dev_base); 26662306a36Sopenharmony_ci if (assert) 26762306a36Sopenharmony_ci val |= BIT(id); 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci val &= ~BIT(id); 27062306a36Sopenharmony_ci writel_relaxed(val, reset->dev_base); 27162306a36Sopenharmony_ci spin_unlock_irqrestore(&reset->lock, flags); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int at91_reset_assert(struct reset_controller_dev *rcdev, 27762306a36Sopenharmony_ci unsigned long id) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci return at91_reset_update(rcdev, id, true); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int at91_reset_deassert(struct reset_controller_dev *rcdev, 28362306a36Sopenharmony_ci unsigned long id) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return at91_reset_update(rcdev, id, false); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int at91_reset_dev_status(struct reset_controller_dev *rcdev, 28962306a36Sopenharmony_ci unsigned long id) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct at91_reset *reset = to_at91_reset(rcdev); 29262306a36Sopenharmony_ci u32 val; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci val = readl_relaxed(reset->dev_base); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return !!(val & BIT(id)); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic const struct reset_control_ops at91_reset_ops = { 30062306a36Sopenharmony_ci .assert = at91_reset_assert, 30162306a36Sopenharmony_ci .deassert = at91_reset_deassert, 30262306a36Sopenharmony_ci .status = at91_reset_dev_status, 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int at91_reset_of_xlate(struct reset_controller_dev *rcdev, 30662306a36Sopenharmony_ci const struct of_phandle_args *reset_spec) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct at91_reset *reset = to_at91_reset(rcdev); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!reset->data->n_device_reset || 31162306a36Sopenharmony_ci (reset_spec->args[0] < reset->data->device_reset_min_id || 31262306a36Sopenharmony_ci reset_spec->args[0] > reset->data->device_reset_max_id)) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return reset_spec->args[0]; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int at91_rcdev_init(struct at91_reset *reset, 31962306a36Sopenharmony_ci struct platform_device *pdev) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci if (!reset->data->n_device_reset) 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci reset->dev_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 1, 32562306a36Sopenharmony_ci NULL); 32662306a36Sopenharmony_ci if (IS_ERR(reset->dev_base)) 32762306a36Sopenharmony_ci return -ENODEV; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci spin_lock_init(&reset->lock); 33062306a36Sopenharmony_ci reset->rcdev.ops = &at91_reset_ops; 33162306a36Sopenharmony_ci reset->rcdev.owner = THIS_MODULE; 33262306a36Sopenharmony_ci reset->rcdev.of_node = pdev->dev.of_node; 33362306a36Sopenharmony_ci reset->rcdev.nr_resets = reset->data->n_device_reset; 33462306a36Sopenharmony_ci reset->rcdev.of_reset_n_cells = 1; 33562306a36Sopenharmony_ci reset->rcdev.of_xlate = at91_reset_of_xlate; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return devm_reset_controller_register(&pdev->dev, &reset->rcdev); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int __init at91_reset_probe(struct platform_device *pdev) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci const struct of_device_id *match; 34362306a36Sopenharmony_ci struct at91_reset *reset; 34462306a36Sopenharmony_ci struct device_node *np; 34562306a36Sopenharmony_ci int ret, idx = 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); 34862306a36Sopenharmony_ci if (!reset) 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci reset->rstc_base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); 35262306a36Sopenharmony_ci if (IS_ERR(reset->rstc_base)) { 35362306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not map reset controller address\n"); 35462306a36Sopenharmony_ci return -ENODEV; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { 35862306a36Sopenharmony_ci /* we need to shutdown the ddr controller, so get ramc base */ 35962306a36Sopenharmony_ci for_each_matching_node_and_match(np, at91_ramc_of_match, &match) { 36062306a36Sopenharmony_ci reset->ramc_lpr = (u32)match->data; 36162306a36Sopenharmony_ci reset->ramc_base[idx] = devm_of_iomap(&pdev->dev, np, 0, NULL); 36262306a36Sopenharmony_ci if (IS_ERR(reset->ramc_base[idx])) { 36362306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not map ram controller address\n"); 36462306a36Sopenharmony_ci of_node_put(np); 36562306a36Sopenharmony_ci return -ENODEV; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci idx++; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci reset->data = device_get_match_data(&pdev->dev); 37262306a36Sopenharmony_ci if (!reset->data) 37362306a36Sopenharmony_ci return -ENODEV; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci reset->nb.notifier_call = at91_reset; 37662306a36Sopenharmony_ci reset->nb.priority = 192; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci reset->sclk = devm_clk_get(&pdev->dev, NULL); 37962306a36Sopenharmony_ci if (IS_ERR(reset->sclk)) 38062306a36Sopenharmony_ci return PTR_ERR(reset->sclk); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ret = clk_prepare_enable(reset->sclk); 38362306a36Sopenharmony_ci if (ret) { 38462306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not enable slow clock\n"); 38562306a36Sopenharmony_ci return ret; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci platform_set_drvdata(pdev, reset); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = at91_rcdev_init(reset, pdev); 39162306a36Sopenharmony_ci if (ret) 39262306a36Sopenharmony_ci goto disable_clk; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (of_device_is_compatible(pdev->dev.of_node, "microchip,sam9x60-rstc")) { 39562306a36Sopenharmony_ci u32 val = readl(reset->rstc_base + AT91_RSTC_MR); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci writel(AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val, 39862306a36Sopenharmony_ci reset->rstc_base + AT91_RSTC_MR); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ret = register_restart_handler(&reset->nb); 40262306a36Sopenharmony_ci if (ret) 40362306a36Sopenharmony_ci goto disable_clk; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = device_create_file(&pdev->dev, &dev_attr_power_on_reason); 40662306a36Sopenharmony_ci if (ret) { 40762306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not create sysfs entry\n"); 40862306a36Sopenharmony_ci return ret; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci dev_info(&pdev->dev, "Starting after %s\n", at91_reset_reason(reset)); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cidisable_clk: 41662306a36Sopenharmony_ci clk_disable_unprepare(reset->sclk); 41762306a36Sopenharmony_ci return ret; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int __exit at91_reset_remove(struct platform_device *pdev) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct at91_reset *reset = platform_get_drvdata(pdev); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci unregister_restart_handler(&reset->nb); 42562306a36Sopenharmony_ci clk_disable_unprepare(reset->sclk); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic struct platform_driver at91_reset_driver = { 43162306a36Sopenharmony_ci .remove = __exit_p(at91_reset_remove), 43262306a36Sopenharmony_ci .driver = { 43362306a36Sopenharmony_ci .name = "at91-reset", 43462306a36Sopenharmony_ci .of_match_table = at91_reset_of_match, 43562306a36Sopenharmony_ci }, 43662306a36Sopenharmony_ci}; 43762306a36Sopenharmony_cimodule_platform_driver_probe(at91_reset_driver, at91_reset_probe); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ciMODULE_AUTHOR("Atmel Corporation"); 44062306a36Sopenharmony_ciMODULE_DESCRIPTION("Reset driver for Atmel SoCs"); 44162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 442