1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2017 Linaro Ltd.
4 * Copyright 2017 ZTE Corporation.
8 #include <linux/component.h>
9 #include <linux/mfd/syscon.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
14 #include <drm/drm_atomic_helper.h>
15 #include <drm/drm_print.h>
16 #include <drm/drm_probe_helper.h>
18 #include "zx_drm_drv.h"
19 #include "zx_tvenc_regs.h"
22 struct zx_tvenc_pwrctrl
{
23 struct regmap
*regmap
;
29 struct drm_connector connector
;
30 struct drm_encoder encoder
;
33 const struct vou_inf
*inf
;
34 struct zx_tvenc_pwrctrl pwrctrl
;
37 #define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
39 struct zx_tvenc_mode
{
40 struct drm_display_mode mode
;
49 u32 line_timing_param
;
51 u32 blank_black_level
;
54 u32 sub_carrier_phase1
;
55 u32 phase_line_incr_cvbs
;
59 * The CRM cannot directly provide a suitable frequency, and we have to
60 * ask a multiplied rate from CRM and use the divider in VOU to get the
63 #define TVENC_CLOCK_MULTIPLIER 4
65 static const struct zx_tvenc_mode tvenc_mode_pal
= {
67 .clock
= 13500 * TVENC_CLOCK_MULTIPLIER
,
69 .hsync_start
= 720 + 12,
70 .hsync_end
= 720 + 12 + 2,
71 .htotal
= 720 + 12 + 2 + 130,
73 .vsync_start
= 576 + 2,
74 .vsync_end
= 576 + 2 + 2,
75 .vtotal
= 576 + 2 + 2 + 20,
76 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
|
77 DRM_MODE_FLAG_INTERLACE
,
79 .video_info
= 0x00040040,
80 .video_res
= 0x05a9c760,
81 .field1_param
= 0x0004d416,
82 .field2_param
= 0x0009b94f,
83 .burst_line_odd1
= 0x0004d406,
84 .burst_line_even1
= 0x0009b53e,
85 .burst_line_odd2
= 0x0004d805,
86 .burst_line_even2
= 0x0009b93f,
87 .line_timing_param
= 0x06a96fdf,
88 .weight_value
= 0x00c188a0,
89 .blank_black_level
= 0x0000fcfc,
90 .burst_level
= 0x00001595,
91 .control_param
= 0x00000001,
92 .sub_carrier_phase1
= 0x1504c566,
93 .phase_line_incr_cvbs
= 0xc068db8c,
96 static const struct zx_tvenc_mode tvenc_mode_ntsc
= {
98 .clock
= 13500 * TVENC_CLOCK_MULTIPLIER
,
100 .hsync_start
= 720 + 16,
101 .hsync_end
= 720 + 16 + 2,
102 .htotal
= 720 + 16 + 2 + 120,
104 .vsync_start
= 480 + 3,
105 .vsync_end
= 480 + 3 + 2,
106 .vtotal
= 480 + 3 + 2 + 17,
107 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
|
108 DRM_MODE_FLAG_INTERLACE
,
110 .video_info
= 0x00040080,
111 .video_res
= 0x05a8375a,
112 .field1_param
= 0x00041817,
113 .field2_param
= 0x0008351e,
114 .burst_line_odd1
= 0x00041006,
115 .burst_line_even1
= 0x0008290d,
116 .burst_line_odd2
= 0x00000000,
117 .burst_line_even2
= 0x00000000,
118 .line_timing_param
= 0x06a8ef9e,
119 .weight_value
= 0x00b68197,
120 .blank_black_level
= 0x0000f0f0,
121 .burst_level
= 0x0000009c,
122 .control_param
= 0x00000001,
123 .sub_carrier_phase1
= 0x10f83e10,
124 .phase_line_incr_cvbs
= 0x80000000,
127 static const struct zx_tvenc_mode
*tvenc_modes
[] = {
132 static const struct zx_tvenc_mode
*
133 zx_tvenc_find_zmode(struct drm_display_mode
*mode
)
137 for (i
= 0; i
< ARRAY_SIZE(tvenc_modes
); i
++) {
138 const struct zx_tvenc_mode
*zmode
= tvenc_modes
[i
];
140 if (drm_mode_equal(mode
, &zmode
->mode
))
147 static void zx_tvenc_encoder_mode_set(struct drm_encoder
*encoder
,
148 struct drm_display_mode
*mode
,
149 struct drm_display_mode
*adj_mode
)
151 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
152 const struct zx_tvenc_mode
*zmode
;
153 struct vou_div_config configs
[] = {
154 { VOU_DIV_INF
, VOU_DIV_4
},
155 { VOU_DIV_TVENC
, VOU_DIV_1
},
156 { VOU_DIV_LAYER
, VOU_DIV_2
},
159 zx_vou_config_dividers(encoder
->crtc
, configs
, ARRAY_SIZE(configs
));
161 zmode
= zx_tvenc_find_zmode(mode
);
163 DRM_DEV_ERROR(tvenc
->dev
, "failed to find zmode\n");
167 zx_writel(tvenc
->mmio
+ VENC_VIDEO_INFO
, zmode
->video_info
);
168 zx_writel(tvenc
->mmio
+ VENC_VIDEO_RES
, zmode
->video_res
);
169 zx_writel(tvenc
->mmio
+ VENC_FIELD1_PARAM
, zmode
->field1_param
);
170 zx_writel(tvenc
->mmio
+ VENC_FIELD2_PARAM
, zmode
->field2_param
);
171 zx_writel(tvenc
->mmio
+ VENC_LINE_O_1
, zmode
->burst_line_odd1
);
172 zx_writel(tvenc
->mmio
+ VENC_LINE_E_1
, zmode
->burst_line_even1
);
173 zx_writel(tvenc
->mmio
+ VENC_LINE_O_2
, zmode
->burst_line_odd2
);
174 zx_writel(tvenc
->mmio
+ VENC_LINE_E_2
, zmode
->burst_line_even2
);
175 zx_writel(tvenc
->mmio
+ VENC_LINE_TIMING_PARAM
,
176 zmode
->line_timing_param
);
177 zx_writel(tvenc
->mmio
+ VENC_WEIGHT_VALUE
, zmode
->weight_value
);
178 zx_writel(tvenc
->mmio
+ VENC_BLANK_BLACK_LEVEL
,
179 zmode
->blank_black_level
);
180 zx_writel(tvenc
->mmio
+ VENC_BURST_LEVEL
, zmode
->burst_level
);
181 zx_writel(tvenc
->mmio
+ VENC_CONTROL_PARAM
, zmode
->control_param
);
182 zx_writel(tvenc
->mmio
+ VENC_SUB_CARRIER_PHASE1
,
183 zmode
->sub_carrier_phase1
);
184 zx_writel(tvenc
->mmio
+ VENC_PHASE_LINE_INCR_CVBS
,
185 zmode
->phase_line_incr_cvbs
);
188 static void zx_tvenc_encoder_enable(struct drm_encoder
*encoder
)
190 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
191 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
193 /* Set bit to power up TVENC DAC */
194 regmap_update_bits(pwrctrl
->regmap
, pwrctrl
->reg
, pwrctrl
->mask
,
197 vou_inf_enable(VOU_TV_ENC
, encoder
->crtc
);
199 zx_writel(tvenc
->mmio
+ VENC_ENABLE
, 1);
202 static void zx_tvenc_encoder_disable(struct drm_encoder
*encoder
)
204 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
205 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
207 zx_writel(tvenc
->mmio
+ VENC_ENABLE
, 0);
209 vou_inf_disable(VOU_TV_ENC
, encoder
->crtc
);
211 /* Clear bit to power down TVENC DAC */
212 regmap_update_bits(pwrctrl
->regmap
, pwrctrl
->reg
, pwrctrl
->mask
, 0);
215 static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs
= {
216 .enable
= zx_tvenc_encoder_enable
,
217 .disable
= zx_tvenc_encoder_disable
,
218 .mode_set
= zx_tvenc_encoder_mode_set
,
221 static const struct drm_encoder_funcs zx_tvenc_encoder_funcs
= {
222 .destroy
= drm_encoder_cleanup
,
225 static int zx_tvenc_connector_get_modes(struct drm_connector
*connector
)
227 struct zx_tvenc
*tvenc
= to_zx_tvenc(connector
);
228 struct device
*dev
= tvenc
->dev
;
231 for (i
= 0; i
< ARRAY_SIZE(tvenc_modes
); i
++) {
232 const struct zx_tvenc_mode
*zmode
= tvenc_modes
[i
];
233 struct drm_display_mode
*mode
;
235 mode
= drm_mode_duplicate(connector
->dev
, &zmode
->mode
);
237 DRM_DEV_ERROR(dev
, "failed to duplicate drm mode\n");
241 drm_mode_set_name(mode
);
242 drm_mode_probed_add(connector
, mode
);
248 static enum drm_mode_status
249 zx_tvenc_connector_mode_valid(struct drm_connector
*connector
,
250 struct drm_display_mode
*mode
)
252 struct zx_tvenc
*tvenc
= to_zx_tvenc(connector
);
253 const struct zx_tvenc_mode
*zmode
;
255 zmode
= zx_tvenc_find_zmode(mode
);
257 DRM_DEV_ERROR(tvenc
->dev
, "unsupported mode: %s\n", mode
->name
);
264 static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs
= {
265 .get_modes
= zx_tvenc_connector_get_modes
,
266 .mode_valid
= zx_tvenc_connector_mode_valid
,
269 static const struct drm_connector_funcs zx_tvenc_connector_funcs
= {
270 .fill_modes
= drm_helper_probe_single_connector_modes
,
271 .destroy
= drm_connector_cleanup
,
272 .reset
= drm_atomic_helper_connector_reset
,
273 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
274 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
277 static int zx_tvenc_register(struct drm_device
*drm
, struct zx_tvenc
*tvenc
)
279 struct drm_encoder
*encoder
= &tvenc
->encoder
;
280 struct drm_connector
*connector
= &tvenc
->connector
;
283 * The tvenc is designed to use aux channel, as there is a deflicker
284 * block for the channel.
286 encoder
->possible_crtcs
= BIT(1);
288 drm_encoder_init(drm
, encoder
, &zx_tvenc_encoder_funcs
,
289 DRM_MODE_ENCODER_TVDAC
, NULL
);
290 drm_encoder_helper_add(encoder
, &zx_tvenc_encoder_helper_funcs
);
292 connector
->interlace_allowed
= true;
294 drm_connector_init(drm
, connector
, &zx_tvenc_connector_funcs
,
295 DRM_MODE_CONNECTOR_Composite
);
296 drm_connector_helper_add(connector
, &zx_tvenc_connector_helper_funcs
);
298 drm_connector_attach_encoder(connector
, encoder
);
303 static int zx_tvenc_pwrctrl_init(struct zx_tvenc
*tvenc
)
305 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
306 struct device
*dev
= tvenc
->dev
;
307 struct of_phandle_args out_args
;
308 struct regmap
*regmap
;
311 ret
= of_parse_phandle_with_fixed_args(dev
->of_node
,
312 "zte,tvenc-power-control", 2, 0, &out_args
);
316 regmap
= syscon_node_to_regmap(out_args
.np
);
317 if (IS_ERR(regmap
)) {
318 ret
= PTR_ERR(regmap
);
322 pwrctrl
->regmap
= regmap
;
323 pwrctrl
->reg
= out_args
.args
[0];
324 pwrctrl
->mask
= out_args
.args
[1];
327 of_node_put(out_args
.np
);
331 static int zx_tvenc_bind(struct device
*dev
, struct device
*master
, void *data
)
333 struct platform_device
*pdev
= to_platform_device(dev
);
334 struct drm_device
*drm
= data
;
335 struct resource
*res
;
336 struct zx_tvenc
*tvenc
;
339 tvenc
= devm_kzalloc(dev
, sizeof(*tvenc
), GFP_KERNEL
);
344 dev_set_drvdata(dev
, tvenc
);
346 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
347 tvenc
->mmio
= devm_ioremap_resource(dev
, res
);
348 if (IS_ERR(tvenc
->mmio
)) {
349 ret
= PTR_ERR(tvenc
->mmio
);
350 DRM_DEV_ERROR(dev
, "failed to remap tvenc region: %d\n", ret
);
354 ret
= zx_tvenc_pwrctrl_init(tvenc
);
356 DRM_DEV_ERROR(dev
, "failed to init power control: %d\n", ret
);
360 ret
= zx_tvenc_register(drm
, tvenc
);
362 DRM_DEV_ERROR(dev
, "failed to register tvenc: %d\n", ret
);
369 static void zx_tvenc_unbind(struct device
*dev
, struct device
*master
,
375 static const struct component_ops zx_tvenc_component_ops
= {
376 .bind
= zx_tvenc_bind
,
377 .unbind
= zx_tvenc_unbind
,
380 static int zx_tvenc_probe(struct platform_device
*pdev
)
382 return component_add(&pdev
->dev
, &zx_tvenc_component_ops
);
385 static int zx_tvenc_remove(struct platform_device
*pdev
)
387 component_del(&pdev
->dev
, &zx_tvenc_component_ops
);
391 static const struct of_device_id zx_tvenc_of_match
[] = {
392 { .compatible
= "zte,zx296718-tvenc", },
395 MODULE_DEVICE_TABLE(of
, zx_tvenc_of_match
);
397 struct platform_driver zx_tvenc_driver
= {
398 .probe
= zx_tvenc_probe
,
399 .remove
= zx_tvenc_remove
,
402 .of_match_table
= zx_tvenc_of_match
,