1 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 and
5  * only version 2 as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12 
13 #include "dpu_hwio.h"
14 #include "dpu_hw_catalog.h"
15 #include "dpu_hw_vbif.h"
16 #include "dpu_dbg.h"
17 
18 #define VBIF_VERSION			0x0000
19 #define VBIF_CLK_FORCE_CTRL0		0x0008
20 #define VBIF_CLK_FORCE_CTRL1		0x000C
21 #define VBIF_QOS_REMAP_00		0x0020
22 #define VBIF_QOS_REMAP_01		0x0024
23 #define VBIF_QOS_REMAP_10		0x0028
24 #define VBIF_QOS_REMAP_11		0x002C
25 #define VBIF_WRITE_GATHER_EN		0x00AC
26 #define VBIF_IN_RD_LIM_CONF0		0x00B0
27 #define VBIF_IN_RD_LIM_CONF1		0x00B4
28 #define VBIF_IN_RD_LIM_CONF2		0x00B8
29 #define VBIF_IN_WR_LIM_CONF0		0x00C0
30 #define VBIF_IN_WR_LIM_CONF1		0x00C4
31 #define VBIF_IN_WR_LIM_CONF2		0x00C8
32 #define VBIF_OUT_RD_LIM_CONF0		0x00D0
33 #define VBIF_OUT_WR_LIM_CONF0		0x00D4
34 #define VBIF_OUT_AXI_AMEMTYPE_CONF0	0x0160
35 #define VBIF_OUT_AXI_AMEMTYPE_CONF1	0x0164
36 #define VBIF_XIN_PND_ERR		0x0190
37 #define VBIF_XIN_SRC_ERR		0x0194
38 #define VBIF_XIN_CLR_ERR		0x019C
39 #define VBIF_XIN_HALT_CTRL0		0x0200
40 #define VBIF_XIN_HALT_CTRL1		0x0204
41 #define VBIF_XINL_QOS_RP_REMAP_000	0x0550
42 #define VBIF_XINL_QOS_LVL_REMAP_000	0x0590
43 
44 static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif,
45 		u32 *pnd_errors, u32 *src_errors)
46 {
47 	struct dpu_hw_blk_reg_map *c;
48 	u32 pnd, src;
49 
50 	if (!vbif)
51 		return;
52 	c = &vbif->hw;
53 	pnd = DPU_REG_READ(c, VBIF_XIN_PND_ERR);
54 	src = DPU_REG_READ(c, VBIF_XIN_SRC_ERR);
55 
56 	if (pnd_errors)
57 		*pnd_errors = pnd;
58 	if (src_errors)
59 		*src_errors = src;
60 
61 	DPU_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src);
62 }
63 
64 static void dpu_hw_set_mem_type(struct dpu_hw_vbif *vbif,
65 		u32 xin_id, u32 value)
66 {
67 	struct dpu_hw_blk_reg_map *c;
68 	u32 reg_off;
69 	u32 bit_off;
70 	u32 reg_val;
71 
72 	/*
73 	 * Assume 4 bits per bit field, 8 fields per 32-bit register so
74 	 * 16 bit fields maximum across two registers
75 	 */
76 	if (!vbif || xin_id >= MAX_XIN_COUNT || xin_id >= 16)
77 		return;
78 
79 	c = &vbif->hw;
80 
81 	if (xin_id >= 8) {
82 		xin_id -= 8;
83 		reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1;
84 	} else {
85 		reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF0;
86 	}
87 	bit_off = (xin_id & 0x7) * 4;
88 	reg_val = DPU_REG_READ(c, reg_off);
89 	reg_val &= ~(0x7 << bit_off);
90 	reg_val |= (value & 0x7) << bit_off;
91 	DPU_REG_WRITE(c, reg_off, reg_val);
92 }
93 
94 static void dpu_hw_set_limit_conf(struct dpu_hw_vbif *vbif,
95 		u32 xin_id, bool rd, u32 limit)
96 {
97 	struct dpu_hw_blk_reg_map *c = &vbif->hw;
98 	u32 reg_val;
99 	u32 reg_off;
100 	u32 bit_off;
101 
102 	if (rd)
103 		reg_off = VBIF_IN_RD_LIM_CONF0;
104 	else
105 		reg_off = VBIF_IN_WR_LIM_CONF0;
106 
107 	reg_off += (xin_id / 4) * 4;
108 	bit_off = (xin_id % 4) * 8;
109 	reg_val = DPU_REG_READ(c, reg_off);
110 	reg_val &= ~(0xFF << bit_off);
111 	reg_val |= (limit) << bit_off;
112 	DPU_REG_WRITE(c, reg_off, reg_val);
113 }
114 
115 static u32 dpu_hw_get_limit_conf(struct dpu_hw_vbif *vbif,
116 		u32 xin_id, bool rd)
117 {
118 	struct dpu_hw_blk_reg_map *c = &vbif->hw;
119 	u32 reg_val;
120 	u32 reg_off;
121 	u32 bit_off;
122 	u32 limit;
123 
124 	if (rd)
125 		reg_off = VBIF_IN_RD_LIM_CONF0;
126 	else
127 		reg_off = VBIF_IN_WR_LIM_CONF0;
128 
129 	reg_off += (xin_id / 4) * 4;
130 	bit_off = (xin_id % 4) * 8;
131 	reg_val = DPU_REG_READ(c, reg_off);
132 	limit = (reg_val >> bit_off) & 0xFF;
133 
134 	return limit;
135 }
136 
137 static void dpu_hw_set_halt_ctrl(struct dpu_hw_vbif *vbif,
138 		u32 xin_id, bool enable)
139 {
140 	struct dpu_hw_blk_reg_map *c = &vbif->hw;
141 	u32 reg_val;
142 
143 	reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL0);
144 
145 	if (enable)
146 		reg_val |= BIT(xin_id);
147 	else
148 		reg_val &= ~BIT(xin_id);
149 
150 	DPU_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val);
151 }
152 
153 static bool dpu_hw_get_halt_ctrl(struct dpu_hw_vbif *vbif,
154 		u32 xin_id)
155 {
156 	struct dpu_hw_blk_reg_map *c = &vbif->hw;
157 	u32 reg_val;
158 
159 	reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL1);
160 
161 	return (reg_val & BIT(xin_id)) ? true : false;
162 }
163 
164 static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif,
165 		u32 xin_id, u32 level, u32 remap_level)
166 {
167 	struct dpu_hw_blk_reg_map *c;
168 	u32 reg_val, reg_val_lvl, mask, reg_high, reg_shift;
169 
170 	if (!vbif)
171 		return;
172 
173 	c = &vbif->hw;
174 
175 	reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8);
176 	reg_shift = (xin_id & 0x7) * 4;
177 
178 	reg_val = DPU_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high);
179 	reg_val_lvl = DPU_REG_READ(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high);
180 
181 	mask = 0x7 << reg_shift;
182 
183 	reg_val &= ~mask;
184 	reg_val |= (remap_level << reg_shift) & mask;
185 
186 	reg_val_lvl &= ~mask;
187 	reg_val_lvl |= (remap_level << reg_shift) & mask;
188 
189 	DPU_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val);
190 	DPU_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl);
191 }
192 
193 static void dpu_hw_set_write_gather_en(struct dpu_hw_vbif *vbif, u32 xin_id)
194 {
195 	struct dpu_hw_blk_reg_map *c;
196 	u32 reg_val;
197 
198 	if (!vbif || xin_id >= MAX_XIN_COUNT)
199 		return;
200 
201 	c = &vbif->hw;
202 
203 	reg_val = DPU_REG_READ(c, VBIF_WRITE_GATHER_EN);
204 	reg_val |= BIT(xin_id);
205 	DPU_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val);
206 }
207 
208 static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops,
209 		unsigned long cap)
210 {
211 	ops->set_limit_conf = dpu_hw_set_limit_conf;
212 	ops->get_limit_conf = dpu_hw_get_limit_conf;
213 	ops->set_halt_ctrl = dpu_hw_set_halt_ctrl;
214 	ops->get_halt_ctrl = dpu_hw_get_halt_ctrl;
215 	if (test_bit(DPU_VBIF_QOS_REMAP, &cap))
216 		ops->set_qos_remap = dpu_hw_set_qos_remap;
217 	ops->set_mem_type = dpu_hw_set_mem_type;
218 	ops->clear_errors = dpu_hw_clear_errors;
219 	ops->set_write_gather_en = dpu_hw_set_write_gather_en;
220 }
221 
222 static const struct dpu_vbif_cfg *_top_offset(enum dpu_vbif vbif,
223 		const struct dpu_mdss_cfg *m,
224 		void __iomem *addr,
225 		struct dpu_hw_blk_reg_map *b)
226 {
227 	int i;
228 
229 	for (i = 0; i < m->vbif_count; i++) {
230 		if (vbif == m->vbif[i].id) {
231 			b->base_off = addr;
232 			b->blk_off = m->vbif[i].base;
233 			b->length = m->vbif[i].len;
234 			b->hwversion = m->hwversion;
235 			b->log_mask = DPU_DBG_MASK_VBIF;
236 			return &m->vbif[i];
237 		}
238 	}
239 
240 	return ERR_PTR(-EINVAL);
241 }
242 
243 struct dpu_hw_vbif *dpu_hw_vbif_init(enum dpu_vbif idx,
244 		void __iomem *addr,
245 		const struct dpu_mdss_cfg *m)
246 {
247 	struct dpu_hw_vbif *c;
248 	const struct dpu_vbif_cfg *cfg;
249 
250 	c = kzalloc(sizeof(*c), GFP_KERNEL);
251 	if (!c)
252 		return ERR_PTR(-ENOMEM);
253 
254 	cfg = _top_offset(idx, m, addr, &c->hw);
255 	if (IS_ERR_OR_NULL(cfg)) {
256 		kfree(c);
257 		return ERR_PTR(-EINVAL);
258 	}
259 
260 	/*
261 	 * Assign ops
262 	 */
263 	c->idx = idx;
264 	c->cap = cfg;
265 	_setup_vbif_ops(&c->ops, c->cap->features);
266 
267 	/* no need to register sub-range in dpu dbg, dump entire vbif io base */
268 
269 	return c;
270 }
271 
272 void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif)
273 {
274 	kfree(vbif);
275 }
276