• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 Loongson Technology Co., Ltd.
4  * Copyright (C) 2019 Lemote Inc.
5  * Authors:
6  *	Chen Zhu <zhuchen@loongson.cn>
7  *	Yaling Fang <fangyaling@loongson.cn>
8  *	Dandan Zhang <zhangdandan@loongson.cn>
9  *	Huacai Chen <chenhc@lemote.com>
10  *	Jiaxun Yang <jiaxun.yang@flygoat.com>
11  */
12 
13 #include <drm/drm_crtc_helper.h>
14 #include "loongson_drv.h"
15 
16 /**
17  * loongson_encoder_destroy
18  *
19  * @encoder: encoder object
20  *
21  * Clean up encoder resources
22  */
loongson_encoder_destroy(struct drm_encoder * encoder)23 static void loongson_encoder_destroy(struct drm_encoder *encoder)
24 {
25 	struct loongson_encoder *loongson_encoder = to_loongson_encoder(encoder);
26 	drm_encoder_cleanup(encoder);
27 	kfree(loongson_encoder);
28 }
29 
loongson_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)30 static int loongson_encoder_atomic_check(struct drm_encoder *encoder,
31 				    struct drm_crtc_state *crtc_state,
32 				    struct drm_connector_state *conn_state)
33 {
34 	return 0;
35 }
36 
loongson_encoder_atomic_mode_set(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)37 static void loongson_encoder_atomic_mode_set(struct drm_encoder *encoder,
38 				struct drm_crtc_state *crtc_state,
39 				struct drm_connector_state *conn_state)
40 {
41 	unsigned long flags;
42 	struct loongson_encoder *lenc = to_loongson_encoder(encoder);
43 	struct loongson_crtc *lcrtc_origin = lenc->lcrtc;
44 	struct loongson_crtc *lcrtc_current = to_loongson_crtc(crtc_state->crtc);
45 
46 	if (lcrtc_origin->crtc_id != lcrtc_current->crtc_id)
47 		lcrtc_origin->cfg_reg |= CFG_PANELSWITCH;
48 	else
49 		lcrtc_origin->cfg_reg &= ~CFG_PANELSWITCH;
50 
51 	spin_lock_irqsave(&loongson_reglock, flags);
52 	crtc_write(lcrtc_origin, FB_CFG_DVO_REG, lcrtc_origin->cfg_reg);
53 	spin_unlock_irqrestore(&loongson_reglock, flags);
54 }
55 
56 /**
57  * These provide the minimum set of functions required to handle a encoder
58  *
59  * Helper operations for encoders
60  */
61 static const struct drm_encoder_helper_funcs loongson_encoder_helper_funcs = {
62 	.atomic_check = loongson_encoder_atomic_check,
63 	.atomic_mode_set = loongson_encoder_atomic_mode_set,
64 };
65 
66 /**
67  * These provide the minimum set of functions required to handle a encoder
68  *
69  * Encoder controls,encoder sit between CRTCs and connectors
70  */
71 static const struct drm_encoder_funcs loongson_encoder_encoder_funcs = {
72 	.destroy = loongson_encoder_destroy,
73 };
74 
loongson_hdmi_init(struct loongson_drm_device * ldev,int index)75 static void loongson_hdmi_init(struct loongson_drm_device *ldev, int index)
76 {
77 	u32 val;
78 	int offset = index * 0x10;
79 	volatile void __iomem *base = ldev->mmio;
80 
81 	spin_lock(&loongson_reglock);
82 	writel(0x287, base + HDMI_CTRL_REG + offset);
83 
84 	writel(0x00400040, base + HDMI_ZONEIDLE_REG + offset);
85 
86 	writel(6272, base + HDMI_AUDIO_NCFG_REG + offset);
87 	writel(0x80000000, base + HDMI_AUDIO_CTSCFG_REG + offset);
88 
89 	writel(0x11, base + HDMI_AUDIO_INFOFRAME_REG + offset);
90 	val = readl(base + HDMI_AUDIO_INFOFRAME_REG + offset) | 0x4;
91 	writel(val, base + HDMI_AUDIO_INFOFRAME_REG + offset);
92 
93 	writel(0x1, base + HDMI_AUDIO_SAMPLE_REG + offset);
94 	spin_unlock(&loongson_reglock);
95 
96 	DRM_DEBUG("Loongson HDMI init finish.\n");
97 }
98 
99 /**
100  * loongson_encoder_init
101  *
102  * @dev: point to the drm_device structure
103  *
104  * Init encoder
105  */
loongson_encoder_init(struct drm_device * dev,unsigned int index)106 struct drm_encoder *loongson_encoder_init(struct drm_device *dev, unsigned int index)
107 {
108 	struct drm_encoder *encoder;
109 	struct loongson_encoder *loongson_encoder;
110 	struct loongson_drm_device *ldev = dev->dev_private;
111 
112 	loongson_encoder = kzalloc(sizeof(struct loongson_encoder), GFP_KERNEL);
113 	if (!loongson_encoder)
114 		return NULL;
115 
116 	loongson_encoder->encoder_id = index;
117 	loongson_encoder->i2c = &ldev->i2c_bus[index];
118 	loongson_encoder->lcrtc = &ldev->lcrtc[index];
119 	loongson_encoder->type = get_encoder_type(ldev, index);
120 	encoder = &loongson_encoder->base;
121 
122 	if (loongson_encoder->type == DRM_MODE_ENCODER_TMDS)
123 		loongson_hdmi_init(ldev, index);
124 
125 	encoder->possible_crtcs = BIT(index);
126 	encoder->possible_clones = BIT(1) | BIT(0);
127 	/* encoder->possible_crtcs = BIT(1) | BIT(0); */
128 
129 	drm_encoder_helper_add(encoder, &loongson_encoder_helper_funcs);
130 	drm_encoder_init(dev, encoder, &loongson_encoder_encoder_funcs,
131 			 loongson_encoder->type, NULL);
132 
133 	return encoder;
134 }
135