162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018, Intel Corporation 462306a36Sopenharmony_ci * Copied from reset-sunxi.c 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/err.h> 862306a36Sopenharmony_ci#include <linux/io.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/of_address.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/reset-controller.h> 1462306a36Sopenharmony_ci#include <linux/reset/reset-simple.h> 1562306a36Sopenharmony_ci#include <linux/reset/socfpga.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define SOCFPGA_NR_BANKS 8 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int a10_reset_init(struct device_node *np) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct reset_simple_data *data; 2562306a36Sopenharmony_ci struct resource res; 2662306a36Sopenharmony_ci resource_size_t size; 2762306a36Sopenharmony_ci int ret; 2862306a36Sopenharmony_ci u32 reg_offset = 0x10; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 3162306a36Sopenharmony_ci if (!data) 3262306a36Sopenharmony_ci return -ENOMEM; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci ret = of_address_to_resource(np, 0, &res); 3562306a36Sopenharmony_ci if (ret) 3662306a36Sopenharmony_ci goto err_alloc; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci size = resource_size(&res); 3962306a36Sopenharmony_ci if (!request_mem_region(res.start, size, np->name)) { 4062306a36Sopenharmony_ci ret = -EBUSY; 4162306a36Sopenharmony_ci goto err_alloc; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci data->membase = ioremap(res.start, size); 4562306a36Sopenharmony_ci if (!data->membase) { 4662306a36Sopenharmony_ci ret = -ENOMEM; 4762306a36Sopenharmony_ci goto release_region; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (of_property_read_u32(np, "altr,modrst-offset", ®_offset)) 5162306a36Sopenharmony_ci pr_warn("missing altr,modrst-offset property, assuming 0x10\n"); 5262306a36Sopenharmony_ci data->membase += reg_offset; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci spin_lock_init(&data->lock); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci data->rcdev.owner = THIS_MODULE; 5762306a36Sopenharmony_ci data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32; 5862306a36Sopenharmony_ci data->rcdev.ops = &reset_simple_ops; 5962306a36Sopenharmony_ci data->rcdev.of_node = np; 6062306a36Sopenharmony_ci data->status_active_low = true; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ret = reset_controller_register(&data->rcdev); 6362306a36Sopenharmony_ci if (ret) 6462306a36Sopenharmony_ci pr_err("unable to register device\n"); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return ret; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cirelease_region: 6962306a36Sopenharmony_ci release_mem_region(res.start, size); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cierr_alloc: 7262306a36Sopenharmony_ci kfree(data); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * These are the reset controller we need to initialize early on in 7862306a36Sopenharmony_ci * our system, before we can even think of using a regular device 7962306a36Sopenharmony_ci * driver for it. 8062306a36Sopenharmony_ci * The controllers that we can register through the regular device 8162306a36Sopenharmony_ci * model are handled by the simple reset driver directly. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic const struct of_device_id socfpga_early_reset_dt_ids[] __initconst = { 8462306a36Sopenharmony_ci { .compatible = "altr,rst-mgr", }, 8562306a36Sopenharmony_ci { /* sentinel */ }, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid __init socfpga_reset_init(void) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct device_node *np; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci for_each_matching_node(np, socfpga_early_reset_dt_ids) 9362306a36Sopenharmony_ci a10_reset_init(np); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * The early driver is problematic, because it doesn't register 9862306a36Sopenharmony_ci * itself as a driver. This causes certain device links to prevent 9962306a36Sopenharmony_ci * consumer devices from probing. The hacky solution is to register 10062306a36Sopenharmony_ci * an empty driver, whose only job is to attach itself to the reset 10162306a36Sopenharmony_ci * manager and call probe. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistatic const struct of_device_id socfpga_reset_dt_ids[] = { 10462306a36Sopenharmony_ci { .compatible = "altr,rst-mgr", }, 10562306a36Sopenharmony_ci { /* sentinel */ }, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int reset_simple_probe(struct platform_device *pdev) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return 0; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic struct platform_driver reset_socfpga_driver = { 11462306a36Sopenharmony_ci .probe = reset_simple_probe, 11562306a36Sopenharmony_ci .driver = { 11662306a36Sopenharmony_ci .name = "socfpga-reset", 11762306a36Sopenharmony_ci .of_match_table = socfpga_reset_dt_ids, 11862306a36Sopenharmony_ci }, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_cibuiltin_platform_driver(reset_socfpga_driver); 121