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 */ 23static 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 30static 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 37static 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 */ 61static 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 */ 71static const struct drm_encoder_funcs loongson_encoder_encoder_funcs = { 72 .destroy = loongson_encoder_destroy, 73}; 74 75static 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 */ 106struct 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