218 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC4 *5 * Authors:6 * Serge Semin <Sergey.Semin@baikalelectronics.ru>7 *8 * Baikal-T1 CCU Resets interface driver9 */10 11#define pr_fmt(fmt) "bt1-ccu-rst: " fmt12 13#include <linux/bits.h>14#include <linux/delay.h>15#include <linux/kernel.h>16#include <linux/of.h>17#include <linux/printk.h>18#include <linux/regmap.h>19#include <linux/reset-controller.h>20#include <linux/slab.h>21 22#include <dt-bindings/reset/bt1-ccu.h>23 24#include "ccu-rst.h"25 26#define CCU_AXI_MAIN_BASE 0x03027#define CCU_AXI_DDR_BASE 0x03428#define CCU_AXI_SATA_BASE 0x03829#define CCU_AXI_GMAC0_BASE 0x03C30#define CCU_AXI_GMAC1_BASE 0x04031#define CCU_AXI_XGMAC_BASE 0x04432#define CCU_AXI_PCIE_M_BASE 0x04833#define CCU_AXI_PCIE_S_BASE 0x04C34#define CCU_AXI_USB_BASE 0x05035#define CCU_AXI_HWA_BASE 0x05436#define CCU_AXI_SRAM_BASE 0x05837 38#define CCU_SYS_DDR_BASE 0x02c39#define CCU_SYS_SATA_REF_BASE 0x06040#define CCU_SYS_APB_BASE 0x06441#define CCU_SYS_PCIE_BASE 0x14442 43#define CCU_RST_DELAY_US 144 45#define CCU_RST_TRIG(_base, _ofs) \46 { \47 .type = CCU_RST_TRIG, \48 .base = _base, \49 .mask = BIT(_ofs), \50 }51 52#define CCU_RST_DIR(_base, _ofs) \53 { \54 .type = CCU_RST_DIR, \55 .base = _base, \56 .mask = BIT(_ofs), \57 }58 59struct ccu_rst_info {60 enum ccu_rst_type type;61 unsigned int base;62 unsigned int mask;63};64 65/*66 * Each AXI-bus clock divider is equipped with the corresponding clock-consumer67 * domain reset (it's self-deasserted reset control).68 */69static const struct ccu_rst_info axi_rst_info[] = {70 [CCU_AXI_MAIN_RST] = CCU_RST_TRIG(CCU_AXI_MAIN_BASE, 1),71 [CCU_AXI_DDR_RST] = CCU_RST_TRIG(CCU_AXI_DDR_BASE, 1),72 [CCU_AXI_SATA_RST] = CCU_RST_TRIG(CCU_AXI_SATA_BASE, 1),73 [CCU_AXI_GMAC0_RST] = CCU_RST_TRIG(CCU_AXI_GMAC0_BASE, 1),74 [CCU_AXI_GMAC1_RST] = CCU_RST_TRIG(CCU_AXI_GMAC1_BASE, 1),75 [CCU_AXI_XGMAC_RST] = CCU_RST_TRIG(CCU_AXI_XGMAC_BASE, 1),76 [CCU_AXI_PCIE_M_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_M_BASE, 1),77 [CCU_AXI_PCIE_S_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_S_BASE, 1),78 [CCU_AXI_USB_RST] = CCU_RST_TRIG(CCU_AXI_USB_BASE, 1),79 [CCU_AXI_HWA_RST] = CCU_RST_TRIG(CCU_AXI_HWA_BASE, 1),80 [CCU_AXI_SRAM_RST] = CCU_RST_TRIG(CCU_AXI_SRAM_BASE, 1),81};82 83/*84 * SATA reference clock domain and APB-bus domain are connected with the85 * sefl-deasserted reset control, which can be activated via the corresponding86 * clock divider register. DDR and PCIe sub-domains can be reset with directly87 * controlled reset signals. Resetting the DDR controller though won't end up88 * well while the Linux kernel is working.89 */90static const struct ccu_rst_info sys_rst_info[] = {91 [CCU_SYS_SATA_REF_RST] = CCU_RST_TRIG(CCU_SYS_SATA_REF_BASE, 1),92 [CCU_SYS_APB_RST] = CCU_RST_TRIG(CCU_SYS_APB_BASE, 1),93 [CCU_SYS_DDR_FULL_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 1),94 [CCU_SYS_DDR_INIT_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 2),95 [CCU_SYS_PCIE_PCS_PHY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 0),96 [CCU_SYS_PCIE_PIPE0_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 4),97 [CCU_SYS_PCIE_CORE_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 8),98 [CCU_SYS_PCIE_PWR_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 9),99 [CCU_SYS_PCIE_STICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 10),100 [CCU_SYS_PCIE_NSTICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 11),101 [CCU_SYS_PCIE_HOT_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 12),102};103 104static int ccu_rst_reset(struct reset_controller_dev *rcdev, unsigned long idx)105{106 struct ccu_rst *rst = to_ccu_rst(rcdev);107 const struct ccu_rst_info *info = &rst->rsts_info[idx];108 109 if (info->type != CCU_RST_TRIG)110 return -EOPNOTSUPP;111 112 regmap_update_bits(rst->sys_regs, info->base, info->mask, info->mask);113 114 /* The next delay must be enough to cover all the resets. */115 udelay(CCU_RST_DELAY_US);116 117 return 0;118}119 120static int ccu_rst_set(struct reset_controller_dev *rcdev,121 unsigned long idx, bool high)122{123 struct ccu_rst *rst = to_ccu_rst(rcdev);124 const struct ccu_rst_info *info = &rst->rsts_info[idx];125 126 if (info->type != CCU_RST_DIR)127 return high ? -EOPNOTSUPP : 0;128 129 return regmap_update_bits(rst->sys_regs, info->base,130 info->mask, high ? info->mask : 0);131}132 133static int ccu_rst_assert(struct reset_controller_dev *rcdev,134 unsigned long idx)135{136 return ccu_rst_set(rcdev, idx, true);137}138 139static int ccu_rst_deassert(struct reset_controller_dev *rcdev,140 unsigned long idx)141{142 return ccu_rst_set(rcdev, idx, false);143}144 145static int ccu_rst_status(struct reset_controller_dev *rcdev,146 unsigned long idx)147{148 struct ccu_rst *rst = to_ccu_rst(rcdev);149 const struct ccu_rst_info *info = &rst->rsts_info[idx];150 u32 val;151 152 if (info->type != CCU_RST_DIR)153 return -EOPNOTSUPP;154 155 regmap_read(rst->sys_regs, info->base, &val);156 157 return !!(val & info->mask);158}159 160static const struct reset_control_ops ccu_rst_ops = {161 .reset = ccu_rst_reset,162 .assert = ccu_rst_assert,163 .deassert = ccu_rst_deassert,164 .status = ccu_rst_status,165};166 167struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *rst_init)168{169 struct ccu_rst *rst;170 int ret;171 172 if (!rst_init)173 return ERR_PTR(-EINVAL);174 175 rst = kzalloc(sizeof(*rst), GFP_KERNEL);176 if (!rst)177 return ERR_PTR(-ENOMEM);178 179 rst->sys_regs = rst_init->sys_regs;180 if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-axi")) {181 rst->rcdev.nr_resets = ARRAY_SIZE(axi_rst_info);182 rst->rsts_info = axi_rst_info;183 } else if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-sys")) {184 rst->rcdev.nr_resets = ARRAY_SIZE(sys_rst_info);185 rst->rsts_info = sys_rst_info;186 } else {187 pr_err("Incompatible DT node '%s' specified\n",188 of_node_full_name(rst_init->np));189 ret = -EINVAL;190 goto err_kfree_rst;191 }192 193 rst->rcdev.owner = THIS_MODULE;194 rst->rcdev.ops = &ccu_rst_ops;195 rst->rcdev.of_node = rst_init->np;196 197 ret = reset_controller_register(&rst->rcdev);198 if (ret) {199 pr_err("Couldn't register '%s' reset controller\n",200 of_node_full_name(rst_init->np));201 goto err_kfree_rst;202 }203 204 return rst;205 206err_kfree_rst:207 kfree(rst);208 209 return ERR_PTR(ret);210}211 212void ccu_rst_hw_unregister(struct ccu_rst *rst)213{214 reset_controller_unregister(&rst->rcdev);215 216 kfree(rst);217}218