xref: /linux/drivers/gpu/drm/imx/dc/dc-ed.c (revision 72856afd33f2fa166c06f1536003e300e51ecf09)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2024 NXP
4  */
5 
6 #include <linux/bitfield.h>
7 #include <linux/bits.h>
8 #include <linux/component.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/regmap.h>
12 
13 #include "dc-drv.h"
14 #include "dc-pe.h"
15 
16 #define PIXENGCFG_STATIC	0x8
17 #define  DIV_MASK		GENMASK(23, 16)
18 #define  DIV(x)			FIELD_PREP(DIV_MASK, (x))
19 #define  DIV_RESET		0x80
20 #define  SYNC_MODE		BIT(8)
21 #define  SINGLE			0
22 #define  POWERDOWN		BIT(4)
23 
24 #define PIXENGCFG_DYNAMIC	0xc
25 
26 #define PIXENGCFG_TRIGGER	0x14
27 #define  SYNC_TRIGGER		BIT(0)
28 
29 #define STATICCONTROL		0x8
30 #define  PERFCOUNTMODE		BIT(12)
31 #define  KICK_MODE		BIT(8)
32 #define  EXTERNAL		BIT(8)
33 
34 #define CONTROL			0xc
35 #define  GAMMAAPPLYENABLE	BIT(0)
36 
37 static const struct dc_subdev_info dc_ed_info[] = {
38 	{ .reg_start = 0x56180980, .id = 0, },
39 	{ .reg_start = 0x56180a00, .id = 1, },
40 	{ .reg_start = 0x561809c0, .id = 4, },
41 	{ .reg_start = 0x56180a40, .id = 5, },
42 };
43 
44 static const struct regmap_range dc_ed_pec_regmap_write_ranges[] = {
45 	regmap_reg_range(PIXENGCFG_STATIC, PIXENGCFG_STATIC),
46 	regmap_reg_range(PIXENGCFG_DYNAMIC, PIXENGCFG_DYNAMIC),
47 	regmap_reg_range(PIXENGCFG_TRIGGER, PIXENGCFG_TRIGGER),
48 };
49 
50 static const struct regmap_access_table dc_ed_pec_regmap_write_table = {
51 	.yes_ranges = dc_ed_pec_regmap_write_ranges,
52 	.n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_write_ranges),
53 };
54 
55 static const struct regmap_range dc_ed_pec_regmap_read_ranges[] = {
56 	regmap_reg_range(PIXENGCFG_STATIC, PIXENGCFG_STATIC),
57 	regmap_reg_range(PIXENGCFG_DYNAMIC, PIXENGCFG_DYNAMIC),
58 };
59 
60 static const struct regmap_access_table dc_ed_pec_regmap_read_table = {
61 	.yes_ranges = dc_ed_pec_regmap_read_ranges,
62 	.n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_read_ranges),
63 };
64 
65 static const struct regmap_range dc_ed_pec_regmap_volatile_ranges[] = {
66 	regmap_reg_range(PIXENGCFG_TRIGGER, PIXENGCFG_TRIGGER),
67 };
68 
69 static const struct regmap_access_table dc_ed_pec_regmap_volatile_table = {
70 	.yes_ranges = dc_ed_pec_regmap_volatile_ranges,
71 	.n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_volatile_ranges),
72 };
73 
74 static const struct regmap_config dc_ed_pec_regmap_config = {
75 	.name = "pec",
76 	.reg_bits = 32,
77 	.reg_stride = 4,
78 	.val_bits = 32,
79 	.fast_io = true,
80 	.wr_table = &dc_ed_pec_regmap_write_table,
81 	.rd_table = &dc_ed_pec_regmap_read_table,
82 	.volatile_table = &dc_ed_pec_regmap_volatile_table,
83 	.max_register = PIXENGCFG_TRIGGER,
84 };
85 
86 static const struct regmap_range dc_ed_regmap_ranges[] = {
87 	regmap_reg_range(STATICCONTROL, STATICCONTROL),
88 	regmap_reg_range(CONTROL, CONTROL),
89 };
90 
91 static const struct regmap_access_table dc_ed_regmap_access_table = {
92 	.yes_ranges = dc_ed_regmap_ranges,
93 	.n_yes_ranges = ARRAY_SIZE(dc_ed_regmap_ranges),
94 };
95 
96 static const struct regmap_config dc_ed_cfg_regmap_config = {
97 	.name = "cfg",
98 	.reg_bits = 32,
99 	.reg_stride = 4,
100 	.val_bits = 32,
101 	.fast_io = true,
102 	.wr_table = &dc_ed_regmap_access_table,
103 	.rd_table = &dc_ed_regmap_access_table,
104 	.max_register = CONTROL,
105 };
106 
107 static const enum dc_link_id src_sels[] = {
108 	LINK_ID_NONE,
109 	LINK_ID_CONSTFRAME0,
110 	LINK_ID_CONSTFRAME1,
111 	LINK_ID_CONSTFRAME4,
112 	LINK_ID_CONSTFRAME5,
113 	LINK_ID_LAYERBLEND3,
114 	LINK_ID_LAYERBLEND2,
115 	LINK_ID_LAYERBLEND1,
116 	LINK_ID_LAYERBLEND0,
117 };
118 
119 static inline void dc_ed_pec_enable_shden(struct dc_ed *ed)
120 {
121 	regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, SHDEN, SHDEN);
122 }
123 
124 static inline void dc_ed_pec_poweron(struct dc_ed *ed)
125 {
126 	regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, POWERDOWN, 0);
127 }
128 
129 static inline void dc_ed_pec_sync_mode_single(struct dc_ed *ed)
130 {
131 	regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, SYNC_MODE, SINGLE);
132 }
133 
134 static inline void dc_ed_pec_div_reset(struct dc_ed *ed)
135 {
136 	regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, DIV_MASK,
137 			  DIV(DIV_RESET));
138 }
139 
140 void dc_ed_pec_src_sel(struct dc_ed *ed, enum dc_link_id src)
141 {
142 	int i;
143 
144 	for (i = 0; i < ARRAY_SIZE(src_sels); i++) {
145 		if (src_sels[i] == src) {
146 			regmap_write(ed->reg_pec, PIXENGCFG_DYNAMIC, src);
147 			return;
148 		}
149 	}
150 }
151 
152 void dc_ed_pec_sync_trigger(struct dc_ed *ed)
153 {
154 	regmap_write(ed->reg_pec, PIXENGCFG_TRIGGER, SYNC_TRIGGER);
155 }
156 
157 static inline void dc_ed_enable_shden(struct dc_ed *ed)
158 {
159 	regmap_write_bits(ed->reg_cfg, STATICCONTROL, SHDEN, SHDEN);
160 }
161 
162 static inline void dc_ed_kick_mode_external(struct dc_ed *ed)
163 {
164 	regmap_write_bits(ed->reg_cfg, STATICCONTROL, KICK_MODE, EXTERNAL);
165 }
166 
167 static inline void dc_ed_disable_perfcountmode(struct dc_ed *ed)
168 {
169 	regmap_write_bits(ed->reg_cfg, STATICCONTROL, PERFCOUNTMODE, 0);
170 }
171 
172 static inline void dc_ed_disable_gamma_apply(struct dc_ed *ed)
173 {
174 	regmap_write_bits(ed->reg_cfg, CONTROL, GAMMAAPPLYENABLE, 0);
175 }
176 
177 void dc_ed_init(struct dc_ed *ed)
178 {
179 	dc_ed_pec_src_sel(ed, LINK_ID_NONE);
180 	dc_ed_pec_enable_shden(ed);
181 	dc_ed_pec_poweron(ed);
182 	dc_ed_pec_sync_mode_single(ed);
183 	dc_ed_pec_div_reset(ed);
184 	dc_ed_enable_shden(ed);
185 	dc_ed_disable_perfcountmode(ed);
186 	dc_ed_kick_mode_external(ed);
187 	dc_ed_disable_gamma_apply(ed);
188 }
189 
190 static int dc_ed_bind(struct device *dev, struct device *master, void *data)
191 {
192 	struct platform_device *pdev = to_platform_device(dev);
193 	struct dc_drm_device *dc_drm = data;
194 	struct resource *res_pec;
195 	void __iomem *base_pec;
196 	void __iomem *base_cfg;
197 	struct dc_ed *ed;
198 	int id;
199 
200 	ed = devm_kzalloc(dev, sizeof(*ed), GFP_KERNEL);
201 	if (!ed)
202 		return -ENOMEM;
203 
204 	base_pec = devm_platform_get_and_ioremap_resource(pdev, 0, &res_pec);
205 	if (IS_ERR(base_pec))
206 		return PTR_ERR(base_pec);
207 
208 	base_cfg = devm_platform_ioremap_resource_byname(pdev, "cfg");
209 	if (IS_ERR(base_cfg))
210 		return PTR_ERR(base_cfg);
211 
212 	ed->reg_pec = devm_regmap_init_mmio(dev, base_pec,
213 					    &dc_ed_pec_regmap_config);
214 	if (IS_ERR(ed->reg_pec))
215 		return PTR_ERR(ed->reg_pec);
216 
217 	ed->reg_cfg = devm_regmap_init_mmio(dev, base_cfg,
218 					    &dc_ed_cfg_regmap_config);
219 	if (IS_ERR(ed->reg_cfg))
220 		return PTR_ERR(ed->reg_cfg);
221 
222 	ed->irq_shdload = platform_get_irq_byname(pdev, "shdload");
223 	if (ed->irq_shdload < 0)
224 		return ed->irq_shdload;
225 
226 	ed->dev = dev;
227 
228 	id = dc_subdev_get_id(dc_ed_info, ARRAY_SIZE(dc_ed_info), res_pec);
229 	if (id < 0) {
230 		dev_err(dev, "failed to get instance number: %d\n", id);
231 		return id;
232 	}
233 
234 	switch (id) {
235 	case 0:
236 		dc_drm->ed_cont[0] = ed;
237 		break;
238 	case 1:
239 		dc_drm->ed_cont[1] = ed;
240 		break;
241 	case 4:
242 		dc_drm->ed_safe[0] = ed;
243 		break;
244 	case 5:
245 		dc_drm->ed_safe[1] = ed;
246 		break;
247 	}
248 
249 	return 0;
250 }
251 
252 static const struct component_ops dc_ed_ops = {
253 	.bind = dc_ed_bind,
254 };
255 
256 static int dc_ed_probe(struct platform_device *pdev)
257 {
258 	int ret;
259 
260 	ret = component_add(&pdev->dev, &dc_ed_ops);
261 	if (ret)
262 		return dev_err_probe(&pdev->dev, ret,
263 				     "failed to add component\n");
264 
265 	return 0;
266 }
267 
268 static void dc_ed_remove(struct platform_device *pdev)
269 {
270 	component_del(&pdev->dev, &dc_ed_ops);
271 }
272 
273 static const struct of_device_id dc_ed_dt_ids[] = {
274 	{ .compatible = "fsl,imx8qxp-dc-extdst" },
275 	{ /* sentinel */ }
276 };
277 MODULE_DEVICE_TABLE(of, dc_ed_dt_ids);
278 
279 struct platform_driver dc_ed_driver = {
280 	.probe = dc_ed_probe,
281 	.remove = dc_ed_remove,
282 	.driver = {
283 		.name = "imx8-dc-extdst",
284 		.suppress_bind_attrs = true,
285 		.of_match_table = dc_ed_dt_ids,
286 	},
287 };
288