brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 40023ea Raw
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