162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Reset controller portions for the U8500 PRCC 462306a36Sopenharmony_ci * Copyright (C) 2021 Linus Walleij <linus.walleij@linaro.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/of.h> 762306a36Sopenharmony_ci#include <linux/of_address.h> 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci#include <linux/reset-controller.h> 1362306a36Sopenharmony_ci#include <linux/bits.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "prcc.h" 1762306a36Sopenharmony_ci#include "reset-prcc.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define to_u8500_prcc_reset(p) container_of((p), struct u8500_prcc_reset, rcdev) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* This macro flattens the 2-dimensional PRCC numberspace */ 2262306a36Sopenharmony_ci#define PRCC_RESET_LINE(prcc_num, bit) \ 2362306a36Sopenharmony_ci (((prcc_num) * PRCC_PERIPHS_PER_CLUSTER) + (bit)) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Reset registers in each PRCC - the reset lines are active low 2762306a36Sopenharmony_ci * so what you need to do is write a bit for the peripheral you 2862306a36Sopenharmony_ci * want to put into reset into the CLEAR register, this will assert 2962306a36Sopenharmony_ci * the reset by pulling the line low. SET take the device out of 3062306a36Sopenharmony_ci * reset. The status reflects the actual state of the line. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#define PRCC_K_SOFTRST_SET 0x018 3362306a36Sopenharmony_ci#define PRCC_K_SOFTRST_CLEAR 0x01c 3462306a36Sopenharmony_ci#define PRCC_K_RST_STATUS 0x020 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int prcc_num_to_index(unsigned int num) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci switch (num) { 3962306a36Sopenharmony_ci case 1: 4062306a36Sopenharmony_ci return CLKRST1_INDEX; 4162306a36Sopenharmony_ci case 2: 4262306a36Sopenharmony_ci return CLKRST2_INDEX; 4362306a36Sopenharmony_ci case 3: 4462306a36Sopenharmony_ci return CLKRST3_INDEX; 4562306a36Sopenharmony_ci case 5: 4662306a36Sopenharmony_ci return CLKRST5_INDEX; 4762306a36Sopenharmony_ci case 6: 4862306a36Sopenharmony_ci return CLKRST6_INDEX; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci return -EINVAL; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void __iomem *u8500_prcc_reset_base(struct u8500_prcc_reset *ur, 5462306a36Sopenharmony_ci unsigned long id) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci unsigned int prcc_num, index; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci prcc_num = id / PRCC_PERIPHS_PER_CLUSTER; 5962306a36Sopenharmony_ci index = prcc_num_to_index(prcc_num); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (index >= ARRAY_SIZE(ur->base)) 6262306a36Sopenharmony_ci return NULL; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return ur->base[index]; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int u8500_prcc_reset(struct reset_controller_dev *rcdev, 6862306a36Sopenharmony_ci unsigned long id) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev); 7162306a36Sopenharmony_ci void __iomem *base = u8500_prcc_reset_base(ur, id); 7262306a36Sopenharmony_ci unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci pr_debug("PRCC cycle reset id %lu, bit %u\n", id, bit); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * Assert reset and then release it. The one microsecond 7862306a36Sopenharmony_ci * delay is found in the vendor reference code. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci writel(BIT(bit), base + PRCC_K_SOFTRST_CLEAR); 8162306a36Sopenharmony_ci udelay(1); 8262306a36Sopenharmony_ci writel(BIT(bit), base + PRCC_K_SOFTRST_SET); 8362306a36Sopenharmony_ci udelay(1); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int u8500_prcc_reset_assert(struct reset_controller_dev *rcdev, 8962306a36Sopenharmony_ci unsigned long id) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev); 9262306a36Sopenharmony_ci void __iomem *base = u8500_prcc_reset_base(ur, id); 9362306a36Sopenharmony_ci unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci pr_debug("PRCC assert reset id %lu, bit %u\n", id, bit); 9662306a36Sopenharmony_ci writel(BIT(bit), base + PRCC_K_SOFTRST_CLEAR); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int u8500_prcc_reset_deassert(struct reset_controller_dev *rcdev, 10262306a36Sopenharmony_ci unsigned long id) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev); 10562306a36Sopenharmony_ci void __iomem *base = u8500_prcc_reset_base(ur, id); 10662306a36Sopenharmony_ci unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci pr_debug("PRCC deassert reset id %lu, bit %u\n", id, bit); 10962306a36Sopenharmony_ci writel(BIT(bit), base + PRCC_K_SOFTRST_SET); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int u8500_prcc_reset_status(struct reset_controller_dev *rcdev, 11562306a36Sopenharmony_ci unsigned long id) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct u8500_prcc_reset *ur = to_u8500_prcc_reset(rcdev); 11862306a36Sopenharmony_ci void __iomem *base = u8500_prcc_reset_base(ur, id); 11962306a36Sopenharmony_ci unsigned int bit = id % PRCC_PERIPHS_PER_CLUSTER; 12062306a36Sopenharmony_ci u32 val; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci pr_debug("PRCC check status on reset line id %lu, bit %u\n", id, bit); 12362306a36Sopenharmony_ci val = readl(base + PRCC_K_RST_STATUS); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Active low so return the inverse value of the bit */ 12662306a36Sopenharmony_ci return !(val & BIT(bit)); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const struct reset_control_ops u8500_prcc_reset_ops = { 13062306a36Sopenharmony_ci .reset = u8500_prcc_reset, 13162306a36Sopenharmony_ci .assert = u8500_prcc_reset_assert, 13262306a36Sopenharmony_ci .deassert = u8500_prcc_reset_deassert, 13362306a36Sopenharmony_ci .status = u8500_prcc_reset_status, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int u8500_prcc_reset_xlate(struct reset_controller_dev *rcdev, 13762306a36Sopenharmony_ci const struct of_phandle_args *reset_spec) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci unsigned int prcc_num, bit; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (reset_spec->args_count != 2) 14262306a36Sopenharmony_ci return -EINVAL; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci prcc_num = reset_spec->args[0]; 14562306a36Sopenharmony_ci bit = reset_spec->args[1]; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (prcc_num != 1 && prcc_num != 2 && prcc_num != 3 && 14862306a36Sopenharmony_ci prcc_num != 5 && prcc_num != 6) { 14962306a36Sopenharmony_ci pr_err("%s: invalid PRCC %d\n", __func__, prcc_num); 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci pr_debug("located reset line %d at PRCC %d bit %d\n", 15462306a36Sopenharmony_ci PRCC_RESET_LINE(prcc_num, bit), prcc_num, bit); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return PRCC_RESET_LINE(prcc_num, bit); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_civoid u8500_prcc_reset_init(struct device_node *np, struct u8500_prcc_reset *ur) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct reset_controller_dev *rcdev = &ur->rcdev; 16262306a36Sopenharmony_ci int ret; 16362306a36Sopenharmony_ci int i; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (i = 0; i < CLKRST_MAX; i++) { 16662306a36Sopenharmony_ci ur->base[i] = ioremap(ur->phy_base[i], SZ_4K); 16762306a36Sopenharmony_ci if (!ur->base[i]) 16862306a36Sopenharmony_ci pr_err("PRCC failed to remap for reset base %d (%08x)\n", 16962306a36Sopenharmony_ci i, ur->phy_base[i]); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci rcdev->owner = THIS_MODULE; 17362306a36Sopenharmony_ci rcdev->ops = &u8500_prcc_reset_ops; 17462306a36Sopenharmony_ci rcdev->of_node = np; 17562306a36Sopenharmony_ci rcdev->of_reset_n_cells = 2; 17662306a36Sopenharmony_ci rcdev->of_xlate = u8500_prcc_reset_xlate; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci ret = reset_controller_register(rcdev); 17962306a36Sopenharmony_ci if (ret) 18062306a36Sopenharmony_ci pr_err("PRCC failed to register reset controller\n"); 18162306a36Sopenharmony_ci} 182