1b3ca9888SDinh Nguyen // SPDX-License-Identifier: GPL-2.0 2b3ca9888SDinh Nguyen /* 3b3ca9888SDinh Nguyen * Copyright (C) 2018, Intel Corporation 4b3ca9888SDinh Nguyen * Copied from reset-sunxi.c 5b3ca9888SDinh Nguyen */ 6b3ca9888SDinh Nguyen 7b3ca9888SDinh Nguyen #include <linux/err.h> 8b3ca9888SDinh Nguyen #include <linux/io.h> 9b3ca9888SDinh Nguyen #include <linux/init.h> 10b3ca9888SDinh Nguyen #include <linux/of.h> 11b3ca9888SDinh Nguyen #include <linux/of_address.h> 12b3ca9888SDinh Nguyen #include <linux/platform_device.h> 13b3ca9888SDinh Nguyen #include <linux/reset-controller.h> 149357b046SMaxime Ripard #include <linux/reset/reset-simple.h> 15cdbeb315SPhilipp Zabel #include <linux/reset/socfpga.h> 16b3ca9888SDinh Nguyen #include <linux/slab.h> 17b3ca9888SDinh Nguyen #include <linux/spinlock.h> 18b3ca9888SDinh Nguyen #include <linux/types.h> 19b3ca9888SDinh Nguyen 20b3ca9888SDinh Nguyen #define SOCFPGA_NR_BANKS 8 21b3ca9888SDinh Nguyen 22b3ca9888SDinh Nguyen static int a10_reset_init(struct device_node *np) 23b3ca9888SDinh Nguyen { 24b3ca9888SDinh Nguyen struct reset_simple_data *data; 25b3ca9888SDinh Nguyen struct resource res; 26b3ca9888SDinh Nguyen resource_size_t size; 27b3ca9888SDinh Nguyen int ret; 28b3ca9888SDinh Nguyen u32 reg_offset = 0x10; 29b3ca9888SDinh Nguyen 30b3ca9888SDinh Nguyen data = kzalloc(sizeof(*data), GFP_KERNEL); 31b3ca9888SDinh Nguyen if (!data) 32b3ca9888SDinh Nguyen return -ENOMEM; 33b3ca9888SDinh Nguyen 34b3ca9888SDinh Nguyen ret = of_address_to_resource(np, 0, &res); 35b3ca9888SDinh Nguyen if (ret) 36b3ca9888SDinh Nguyen goto err_alloc; 37b3ca9888SDinh Nguyen 38b3ca9888SDinh Nguyen size = resource_size(&res); 39b3ca9888SDinh Nguyen if (!request_mem_region(res.start, size, np->name)) { 40b3ca9888SDinh Nguyen ret = -EBUSY; 41b3ca9888SDinh Nguyen goto err_alloc; 42b3ca9888SDinh Nguyen } 43b3ca9888SDinh Nguyen 44b3ca9888SDinh Nguyen data->membase = ioremap(res.start, size); 45b3ca9888SDinh Nguyen if (!data->membase) { 46b3ca9888SDinh Nguyen ret = -ENOMEM; 470d625a16SDinh Nguyen goto release_region; 48b3ca9888SDinh Nguyen } 49b3ca9888SDinh Nguyen 50b3ca9888SDinh Nguyen if (of_property_read_u32(np, "altr,modrst-offset", ®_offset)) 51b3ca9888SDinh Nguyen pr_warn("missing altr,modrst-offset property, assuming 0x10\n"); 52b3ca9888SDinh Nguyen data->membase += reg_offset; 53b3ca9888SDinh Nguyen 54b3ca9888SDinh Nguyen spin_lock_init(&data->lock); 55b3ca9888SDinh Nguyen 56b3ca9888SDinh Nguyen data->rcdev.owner = THIS_MODULE; 57b3ca9888SDinh Nguyen data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32; 58b3ca9888SDinh Nguyen data->rcdev.ops = &reset_simple_ops; 59b3ca9888SDinh Nguyen data->rcdev.of_node = np; 60b3ca9888SDinh Nguyen data->status_active_low = true; 61b3ca9888SDinh Nguyen 620d625a16SDinh Nguyen ret = reset_controller_register(&data->rcdev); 630d625a16SDinh Nguyen if (ret) 640d625a16SDinh Nguyen pr_err("unable to register device\n"); 650d625a16SDinh Nguyen 660d625a16SDinh Nguyen return ret; 670d625a16SDinh Nguyen 680d625a16SDinh Nguyen release_region: 690d625a16SDinh Nguyen release_mem_region(res.start, size); 70b3ca9888SDinh Nguyen 71b3ca9888SDinh Nguyen err_alloc: 72b3ca9888SDinh Nguyen kfree(data); 73b3ca9888SDinh Nguyen return ret; 74b3ca9888SDinh Nguyen }; 75b3ca9888SDinh Nguyen 76b3ca9888SDinh Nguyen /* 77b3ca9888SDinh Nguyen * These are the reset controller we need to initialize early on in 78b3ca9888SDinh Nguyen * our system, before we can even think of using a regular device 79b3ca9888SDinh Nguyen * driver for it. 80b3ca9888SDinh Nguyen * The controllers that we can register through the regular device 81b3ca9888SDinh Nguyen * model are handled by the simple reset driver directly. 82b3ca9888SDinh Nguyen */ 83b3ca9888SDinh Nguyen static const struct of_device_id socfpga_early_reset_dt_ids[] __initconst = { 84b3ca9888SDinh Nguyen { .compatible = "altr,rst-mgr", }, 85b3ca9888SDinh Nguyen { /* sentinel */ }, 86b3ca9888SDinh Nguyen }; 87b3ca9888SDinh Nguyen 88b3ca9888SDinh Nguyen void __init socfpga_reset_init(void) 89b3ca9888SDinh Nguyen { 90b3ca9888SDinh Nguyen struct device_node *np; 91b3ca9888SDinh Nguyen 92b3ca9888SDinh Nguyen for_each_matching_node(np, socfpga_early_reset_dt_ids) 93b3ca9888SDinh Nguyen a10_reset_init(np); 94b3ca9888SDinh Nguyen } 95*3ad60b4bSPaweł Anikiel 96*3ad60b4bSPaweł Anikiel /* 97*3ad60b4bSPaweł Anikiel * The early driver is problematic, because it doesn't register 98*3ad60b4bSPaweł Anikiel * itself as a driver. This causes certain device links to prevent 99*3ad60b4bSPaweł Anikiel * consumer devices from probing. The hacky solution is to register 100*3ad60b4bSPaweł Anikiel * an empty driver, whose only job is to attach itself to the reset 101*3ad60b4bSPaweł Anikiel * manager and call probe. 102*3ad60b4bSPaweł Anikiel */ 103*3ad60b4bSPaweł Anikiel static const struct of_device_id socfpga_reset_dt_ids[] = { 104*3ad60b4bSPaweł Anikiel { .compatible = "altr,rst-mgr", }, 105*3ad60b4bSPaweł Anikiel { /* sentinel */ }, 106*3ad60b4bSPaweł Anikiel }; 107*3ad60b4bSPaweł Anikiel 108*3ad60b4bSPaweł Anikiel static int reset_simple_probe(struct platform_device *pdev) 109*3ad60b4bSPaweł Anikiel { 110*3ad60b4bSPaweł Anikiel return 0; 111*3ad60b4bSPaweł Anikiel } 112*3ad60b4bSPaweł Anikiel 113*3ad60b4bSPaweł Anikiel static struct platform_driver reset_socfpga_driver = { 114*3ad60b4bSPaweł Anikiel .probe = reset_simple_probe, 115*3ad60b4bSPaweł Anikiel .driver = { 116*3ad60b4bSPaweł Anikiel .name = "socfpga-reset", 117*3ad60b4bSPaweł Anikiel .of_match_table = socfpga_reset_dt_ids, 118*3ad60b4bSPaweł Anikiel }, 119*3ad60b4bSPaweł Anikiel }; 120*3ad60b4bSPaweł Anikiel builtin_platform_driver(reset_socfpga_driver); 121