blob: 2e695a62f0c7b73a1bbd4593fba33047d3a874e4 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Owen Chen <Owen.Chen@mediatek.com>
5 */
6#include <linux/ktime.h>
7#include <linux/mfd/syscon.h>
8#include <linux/of_device.h>
9#include <linux/regmap.h>
10#include <linux/soc/mediatek/scpsys-ext.h>
11
12#define MTK_POLL_DELAY_US 10
13#define MTK_POLL_TIMEOUT USEC_PER_SEC
14
15static int enable_way_en(struct regmap *map, struct regmap *ack, u32 mask,
16 u32 ack_mask, u32 reg_set, u32 reg_sta,
17 u32 reg_en)
18{
19 u32 val = 0;
20
21 if (reg_set)
22 regmap_write(map, reg_set, mask);
23 else
24 regmap_update_bits(map, reg_en, mask, mask);
25
26 return regmap_read_poll_timeout(ack, reg_sta,
27 val, (val & ack_mask) == ack_mask,
28 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
29}
30
31static int disable_way_en(struct regmap *map, struct regmap *ack, u32 mask,
32 u32 ack_mask, u32 reg_clr, u32 reg_sta,
33 u32 reg_en)
34{
35 u32 val = 0;
36
37 if (reg_clr)
38 regmap_write(map, reg_clr, mask);
39 else
40 regmap_update_bits(map, reg_en, mask, 0);
41
42 return regmap_read_poll_timeout(ack, reg_sta,
43 val, (val & ack_mask) == ack_mask,
44 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
45}
46
47static int set_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
48 u32 reg_set, u32 reg_sta, u32 reg_en)
49{
50 u32 val = 0;
51
52 if (reg_set)
53 regmap_write(map, reg_set, mask);
54 else
55 regmap_update_bits(map, reg_en, mask, mask);
56
57 return regmap_read_poll_timeout(map, reg_sta,
58 val, (val & ack_mask) == ack_mask,
59 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
60}
61
62static int clear_bus_protection(struct regmap *map, u32 mask, u32 ack_mask,
63 u32 reg_clr, u32 reg_sta, u32 reg_en)
64{
65 u32 val = 0;
66
67 if (reg_clr)
68 regmap_write(map, reg_clr, mask);
69 else
70 regmap_update_bits(map, reg_en, mask, 0);
71
72 return regmap_read_poll_timeout(map, reg_sta,
73 val, !(val & ack_mask),
74 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
75}
76
77int mtk_scpsys_ext_set_bus_protection(const struct bus_prot *bp_table,
78 struct regmap *infracfg, struct regmap *smi_common,
79 struct regmap *infracfg_nao)
80{
81 int i;
82
83 for (i = 0; i < MAX_STEPS && bp_table[i].mask; i++) {
84 int ret;
85
86 switch (bp_table[i].type) {
87 case IFR_TYPE:
88 ret = set_bus_protection(infracfg, bp_table[i].mask,
89 bp_table[i].mask, bp_table[i].set_ofs,
90 bp_table[i].sta_ofs,
91 bp_table[i].en_ofs);
92 break;
93 case SMI_TYPE:
94 ret = set_bus_protection(smi_common, bp_table[i].mask,
95 bp_table[i].mask, bp_table[i].set_ofs,
96 bp_table[i].sta_ofs,
97 bp_table[i].en_ofs);
98 break;
99 case IFR_WAYEN_TYPE:
100 ret = disable_way_en(infracfg, infracfg_nao,
101 bp_table[i].mask,
102 bp_table[i].clr_ack_mask,
103 bp_table[i].clr_ofs,
104 bp_table[i].sta_ofs,
105 bp_table[i].en_ofs);
106 break;
107 default:
108 return -EINVAL;
109 }
110
111 if (ret)
112 return ret;
113 }
114
115 return 0;
116}
117
118int mtk_scpsys_ext_clear_bus_protection(const struct bus_prot *bp_table,
119 struct regmap *infracfg, struct regmap *smi_common,
120 struct regmap *infracfg_nao)
121{
122 int i;
123
124 for (i = MAX_STEPS - 1; i >= 0; i--) {
125 int ret;
126
127 switch (bp_table[i].type) {
128 case IFR_TYPE:
129 ret = clear_bus_protection(infracfg, bp_table[i].mask,
130 bp_table[i].clr_ack_mask,
131 bp_table[i].clr_ofs,
132 bp_table[i].sta_ofs,
133 bp_table[i].en_ofs);
134 break;
135 case SMI_TYPE:
136 ret = clear_bus_protection(smi_common,
137 bp_table[i].mask,
138 bp_table[i].clr_ack_mask,
139 bp_table[i].clr_ofs,
140 bp_table[i].sta_ofs,
141 bp_table[i].en_ofs);
142 break;
143 case IFR_WAYEN_TYPE:
144 ret = enable_way_en(infracfg, infracfg_nao,
145 bp_table[i].mask,
146 bp_table[i].set_ack_mask,
147 bp_table[i].set_ofs,
148 bp_table[i].sta_ofs,
149 bp_table[i].en_ofs);
150 break;
151 default:
152 return -EINVAL;
153 }
154
155 if (ret)
156 return ret;
157 }
158
159 return 0;
160}