170fa8954SSerge Semin // SPDX-License-Identifier: GPL-2.0-only
270fa8954SSerge Semin /*
370fa8954SSerge Semin * Copyright (C) 2021 BAIKAL ELECTRONICS, JSC
470fa8954SSerge Semin *
570fa8954SSerge Semin * Authors:
670fa8954SSerge Semin * Serge Semin <Sergey.Semin@baikalelectronics.ru>
770fa8954SSerge Semin *
870fa8954SSerge Semin * Baikal-T1 CCU Resets interface driver
970fa8954SSerge Semin */
1070fa8954SSerge Semin
1170fa8954SSerge Semin #define pr_fmt(fmt) "bt1-ccu-rst: " fmt
1270fa8954SSerge Semin
1370fa8954SSerge Semin #include <linux/bits.h>
1470fa8954SSerge Semin #include <linux/delay.h>
1570fa8954SSerge Semin #include <linux/kernel.h>
1670fa8954SSerge Semin #include <linux/of.h>
1770fa8954SSerge Semin #include <linux/printk.h>
1870fa8954SSerge Semin #include <linux/regmap.h>
1970fa8954SSerge Semin #include <linux/reset-controller.h>
2070fa8954SSerge Semin #include <linux/slab.h>
2170fa8954SSerge Semin
2270fa8954SSerge Semin #include <dt-bindings/reset/bt1-ccu.h>
2370fa8954SSerge Semin
2470fa8954SSerge Semin #include "ccu-rst.h"
2570fa8954SSerge Semin
2670fa8954SSerge Semin #define CCU_AXI_MAIN_BASE 0x030
2770fa8954SSerge Semin #define CCU_AXI_DDR_BASE 0x034
2870fa8954SSerge Semin #define CCU_AXI_SATA_BASE 0x038
2970fa8954SSerge Semin #define CCU_AXI_GMAC0_BASE 0x03C
3070fa8954SSerge Semin #define CCU_AXI_GMAC1_BASE 0x040
3170fa8954SSerge Semin #define CCU_AXI_XGMAC_BASE 0x044
3270fa8954SSerge Semin #define CCU_AXI_PCIE_M_BASE 0x048
3370fa8954SSerge Semin #define CCU_AXI_PCIE_S_BASE 0x04C
3470fa8954SSerge Semin #define CCU_AXI_USB_BASE 0x050
3570fa8954SSerge Semin #define CCU_AXI_HWA_BASE 0x054
3670fa8954SSerge Semin #define CCU_AXI_SRAM_BASE 0x058
3770fa8954SSerge Semin
38*fa6bd541SSerge Semin #define CCU_SYS_DDR_BASE 0x02c
3970fa8954SSerge Semin #define CCU_SYS_SATA_REF_BASE 0x060
4070fa8954SSerge Semin #define CCU_SYS_APB_BASE 0x064
41*fa6bd541SSerge Semin #define CCU_SYS_PCIE_BASE 0x144
4270fa8954SSerge Semin
4370fa8954SSerge Semin #define CCU_RST_DELAY_US 1
4470fa8954SSerge Semin
4570fa8954SSerge Semin #define CCU_RST_TRIG(_base, _ofs) \
4670fa8954SSerge Semin { \
47*fa6bd541SSerge Semin .type = CCU_RST_TRIG, \
48*fa6bd541SSerge Semin .base = _base, \
49*fa6bd541SSerge Semin .mask = BIT(_ofs), \
50*fa6bd541SSerge Semin }
51*fa6bd541SSerge Semin
52*fa6bd541SSerge Semin #define CCU_RST_DIR(_base, _ofs) \
53*fa6bd541SSerge Semin { \
54*fa6bd541SSerge Semin .type = CCU_RST_DIR, \
5570fa8954SSerge Semin .base = _base, \
5670fa8954SSerge Semin .mask = BIT(_ofs), \
5770fa8954SSerge Semin }
5870fa8954SSerge Semin
5970fa8954SSerge Semin struct ccu_rst_info {
60*fa6bd541SSerge Semin enum ccu_rst_type type;
6170fa8954SSerge Semin unsigned int base;
6270fa8954SSerge Semin unsigned int mask;
6370fa8954SSerge Semin };
6470fa8954SSerge Semin
6570fa8954SSerge Semin /*
6670fa8954SSerge Semin * Each AXI-bus clock divider is equipped with the corresponding clock-consumer
6770fa8954SSerge Semin * domain reset (it's self-deasserted reset control).
6870fa8954SSerge Semin */
6970fa8954SSerge Semin static const struct ccu_rst_info axi_rst_info[] = {
7070fa8954SSerge Semin [CCU_AXI_MAIN_RST] = CCU_RST_TRIG(CCU_AXI_MAIN_BASE, 1),
7170fa8954SSerge Semin [CCU_AXI_DDR_RST] = CCU_RST_TRIG(CCU_AXI_DDR_BASE, 1),
7270fa8954SSerge Semin [CCU_AXI_SATA_RST] = CCU_RST_TRIG(CCU_AXI_SATA_BASE, 1),
7370fa8954SSerge Semin [CCU_AXI_GMAC0_RST] = CCU_RST_TRIG(CCU_AXI_GMAC0_BASE, 1),
7470fa8954SSerge Semin [CCU_AXI_GMAC1_RST] = CCU_RST_TRIG(CCU_AXI_GMAC1_BASE, 1),
7570fa8954SSerge Semin [CCU_AXI_XGMAC_RST] = CCU_RST_TRIG(CCU_AXI_XGMAC_BASE, 1),
7670fa8954SSerge Semin [CCU_AXI_PCIE_M_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_M_BASE, 1),
7770fa8954SSerge Semin [CCU_AXI_PCIE_S_RST] = CCU_RST_TRIG(CCU_AXI_PCIE_S_BASE, 1),
7870fa8954SSerge Semin [CCU_AXI_USB_RST] = CCU_RST_TRIG(CCU_AXI_USB_BASE, 1),
7970fa8954SSerge Semin [CCU_AXI_HWA_RST] = CCU_RST_TRIG(CCU_AXI_HWA_BASE, 1),
8070fa8954SSerge Semin [CCU_AXI_SRAM_RST] = CCU_RST_TRIG(CCU_AXI_SRAM_BASE, 1),
8170fa8954SSerge Semin };
8270fa8954SSerge Semin
8370fa8954SSerge Semin /*
8470fa8954SSerge Semin * SATA reference clock domain and APB-bus domain are connected with the
8570fa8954SSerge Semin * sefl-deasserted reset control, which can be activated via the corresponding
8670fa8954SSerge Semin * clock divider register. DDR and PCIe sub-domains can be reset with directly
8770fa8954SSerge Semin * controlled reset signals. Resetting the DDR controller though won't end up
8870fa8954SSerge Semin * well while the Linux kernel is working.
8970fa8954SSerge Semin */
9070fa8954SSerge Semin static const struct ccu_rst_info sys_rst_info[] = {
9170fa8954SSerge Semin [CCU_SYS_SATA_REF_RST] = CCU_RST_TRIG(CCU_SYS_SATA_REF_BASE, 1),
9270fa8954SSerge Semin [CCU_SYS_APB_RST] = CCU_RST_TRIG(CCU_SYS_APB_BASE, 1),
93*fa6bd541SSerge Semin [CCU_SYS_DDR_FULL_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 1),
94*fa6bd541SSerge Semin [CCU_SYS_DDR_INIT_RST] = CCU_RST_DIR(CCU_SYS_DDR_BASE, 2),
95*fa6bd541SSerge Semin [CCU_SYS_PCIE_PCS_PHY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 0),
96*fa6bd541SSerge Semin [CCU_SYS_PCIE_PIPE0_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 4),
97*fa6bd541SSerge Semin [CCU_SYS_PCIE_CORE_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 8),
98*fa6bd541SSerge Semin [CCU_SYS_PCIE_PWR_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 9),
99*fa6bd541SSerge Semin [CCU_SYS_PCIE_STICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 10),
100*fa6bd541SSerge Semin [CCU_SYS_PCIE_NSTICKY_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 11),
101*fa6bd541SSerge Semin [CCU_SYS_PCIE_HOT_RST] = CCU_RST_DIR(CCU_SYS_PCIE_BASE, 12),
10270fa8954SSerge Semin };
10370fa8954SSerge Semin
ccu_rst_reset(struct reset_controller_dev * rcdev,unsigned long idx)10470fa8954SSerge Semin static int ccu_rst_reset(struct reset_controller_dev *rcdev, unsigned long idx)
10570fa8954SSerge Semin {
10670fa8954SSerge Semin struct ccu_rst *rst = to_ccu_rst(rcdev);
10770fa8954SSerge Semin const struct ccu_rst_info *info = &rst->rsts_info[idx];
10870fa8954SSerge Semin
109*fa6bd541SSerge Semin if (info->type != CCU_RST_TRIG)
110*fa6bd541SSerge Semin return -EOPNOTSUPP;
111*fa6bd541SSerge Semin
11270fa8954SSerge Semin regmap_update_bits(rst->sys_regs, info->base, info->mask, info->mask);
11370fa8954SSerge Semin
11470fa8954SSerge Semin /* The next delay must be enough to cover all the resets. */
11570fa8954SSerge Semin udelay(CCU_RST_DELAY_US);
11670fa8954SSerge Semin
11770fa8954SSerge Semin return 0;
11870fa8954SSerge Semin }
11970fa8954SSerge Semin
ccu_rst_set(struct reset_controller_dev * rcdev,unsigned long idx,bool high)120*fa6bd541SSerge Semin static int ccu_rst_set(struct reset_controller_dev *rcdev,
121*fa6bd541SSerge Semin unsigned long idx, bool high)
122*fa6bd541SSerge Semin {
123*fa6bd541SSerge Semin struct ccu_rst *rst = to_ccu_rst(rcdev);
124*fa6bd541SSerge Semin const struct ccu_rst_info *info = &rst->rsts_info[idx];
125*fa6bd541SSerge Semin
126*fa6bd541SSerge Semin if (info->type != CCU_RST_DIR)
127*fa6bd541SSerge Semin return high ? -EOPNOTSUPP : 0;
128*fa6bd541SSerge Semin
129*fa6bd541SSerge Semin return regmap_update_bits(rst->sys_regs, info->base,
130*fa6bd541SSerge Semin info->mask, high ? info->mask : 0);
131*fa6bd541SSerge Semin }
132*fa6bd541SSerge Semin
ccu_rst_assert(struct reset_controller_dev * rcdev,unsigned long idx)133*fa6bd541SSerge Semin static int ccu_rst_assert(struct reset_controller_dev *rcdev,
134*fa6bd541SSerge Semin unsigned long idx)
135*fa6bd541SSerge Semin {
136*fa6bd541SSerge Semin return ccu_rst_set(rcdev, idx, true);
137*fa6bd541SSerge Semin }
138*fa6bd541SSerge Semin
ccu_rst_deassert(struct reset_controller_dev * rcdev,unsigned long idx)139*fa6bd541SSerge Semin static int ccu_rst_deassert(struct reset_controller_dev *rcdev,
140*fa6bd541SSerge Semin unsigned long idx)
141*fa6bd541SSerge Semin {
142*fa6bd541SSerge Semin return ccu_rst_set(rcdev, idx, false);
143*fa6bd541SSerge Semin }
144*fa6bd541SSerge Semin
ccu_rst_status(struct reset_controller_dev * rcdev,unsigned long idx)145*fa6bd541SSerge Semin static int ccu_rst_status(struct reset_controller_dev *rcdev,
146*fa6bd541SSerge Semin unsigned long idx)
147*fa6bd541SSerge Semin {
148*fa6bd541SSerge Semin struct ccu_rst *rst = to_ccu_rst(rcdev);
149*fa6bd541SSerge Semin const struct ccu_rst_info *info = &rst->rsts_info[idx];
150*fa6bd541SSerge Semin u32 val;
151*fa6bd541SSerge Semin
152*fa6bd541SSerge Semin if (info->type != CCU_RST_DIR)
153*fa6bd541SSerge Semin return -EOPNOTSUPP;
154*fa6bd541SSerge Semin
155*fa6bd541SSerge Semin regmap_read(rst->sys_regs, info->base, &val);
156*fa6bd541SSerge Semin
157*fa6bd541SSerge Semin return !!(val & info->mask);
158*fa6bd541SSerge Semin }
159*fa6bd541SSerge Semin
16070fa8954SSerge Semin static const struct reset_control_ops ccu_rst_ops = {
16170fa8954SSerge Semin .reset = ccu_rst_reset,
162*fa6bd541SSerge Semin .assert = ccu_rst_assert,
163*fa6bd541SSerge Semin .deassert = ccu_rst_deassert,
164*fa6bd541SSerge Semin .status = ccu_rst_status,
16570fa8954SSerge Semin };
16670fa8954SSerge Semin
ccu_rst_hw_register(const struct ccu_rst_init_data * rst_init)16770fa8954SSerge Semin struct ccu_rst *ccu_rst_hw_register(const struct ccu_rst_init_data *rst_init)
16870fa8954SSerge Semin {
16970fa8954SSerge Semin struct ccu_rst *rst;
17070fa8954SSerge Semin int ret;
17170fa8954SSerge Semin
17270fa8954SSerge Semin if (!rst_init)
17370fa8954SSerge Semin return ERR_PTR(-EINVAL);
17470fa8954SSerge Semin
17570fa8954SSerge Semin rst = kzalloc(sizeof(*rst), GFP_KERNEL);
17670fa8954SSerge Semin if (!rst)
17770fa8954SSerge Semin return ERR_PTR(-ENOMEM);
17870fa8954SSerge Semin
17970fa8954SSerge Semin rst->sys_regs = rst_init->sys_regs;
18070fa8954SSerge Semin if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-axi")) {
18170fa8954SSerge Semin rst->rcdev.nr_resets = ARRAY_SIZE(axi_rst_info);
18270fa8954SSerge Semin rst->rsts_info = axi_rst_info;
18370fa8954SSerge Semin } else if (of_device_is_compatible(rst_init->np, "baikal,bt1-ccu-sys")) {
18470fa8954SSerge Semin rst->rcdev.nr_resets = ARRAY_SIZE(sys_rst_info);
18570fa8954SSerge Semin rst->rsts_info = sys_rst_info;
18670fa8954SSerge Semin } else {
18770fa8954SSerge Semin pr_err("Incompatible DT node '%s' specified\n",
18870fa8954SSerge Semin of_node_full_name(rst_init->np));
18970fa8954SSerge Semin ret = -EINVAL;
19070fa8954SSerge Semin goto err_kfree_rst;
19170fa8954SSerge Semin }
19270fa8954SSerge Semin
19370fa8954SSerge Semin rst->rcdev.owner = THIS_MODULE;
19470fa8954SSerge Semin rst->rcdev.ops = &ccu_rst_ops;
19570fa8954SSerge Semin rst->rcdev.of_node = rst_init->np;
19670fa8954SSerge Semin
19770fa8954SSerge Semin ret = reset_controller_register(&rst->rcdev);
19870fa8954SSerge Semin if (ret) {
19970fa8954SSerge Semin pr_err("Couldn't register '%s' reset controller\n",
20070fa8954SSerge Semin of_node_full_name(rst_init->np));
20170fa8954SSerge Semin goto err_kfree_rst;
20270fa8954SSerge Semin }
20370fa8954SSerge Semin
20470fa8954SSerge Semin return rst;
20570fa8954SSerge Semin
20670fa8954SSerge Semin err_kfree_rst:
20770fa8954SSerge Semin kfree(rst);
20870fa8954SSerge Semin
20970fa8954SSerge Semin return ERR_PTR(ret);
21070fa8954SSerge Semin }
21170fa8954SSerge Semin
ccu_rst_hw_unregister(struct ccu_rst * rst)21270fa8954SSerge Semin void ccu_rst_hw_unregister(struct ccu_rst *rst)
21370fa8954SSerge Semin {
21470fa8954SSerge Semin reset_controller_unregister(&rst->rcdev);
21570fa8954SSerge Semin
21670fa8954SSerge Semin kfree(rst);
21770fa8954SSerge Semin }
218