brintos

brintos / linux-shallow public Read only

0
0
Text · 5.0 KiB · 600ed4f Raw
178 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2023 Loongson Technology Corporation Limited4 */5 6#include <drm/drm_atomic_helper.h>7#include <drm/drm_edid.h>8#include <drm/drm_probe_helper.h>9 10#include "lsdc_drv.h"11#include "lsdc_output.h"12 13/*14 * The display controller in the LS7A1000 exports two DVO interfaces, thus15 * external encoder is required, except connected to the DPI panel directly.16 *17 *       ___________________                                     _________18 *      |            -------|                                   |         |19 *      |  CRTC0 --> | DVO0 ----> Encoder0 ---> Connector0 ---> | Display |20 *      |  _   _     -------|        ^             ^            |_________|21 *      | | | | |  +------+ |        |             |22 *      | |_| |_|  | i2c6 | <--------+-------------+23 *      |          +------+ |24 *      |                   |25 *      |  DC in LS7A1000   |26 *      |                   |27 *      |  _   _   +------+ |28 *      | | | | |  | i2c7 | <--------+-------------+29 *      | |_| |_|  +------+ |        |             |             _________30 *      |            -------|        |             |            |         |31 *      |  CRTC1 --> | DVO1 ----> Encoder1 ---> Connector1 ---> |  Panel  |32 *      |            -------|                                   |_________|33 *      |___________________|34 *35 * Currently, we assume the external encoders connected to the DVO are36 * transparent. Loongson's DVO interface can directly drive RGB888 panels.37 *38 *  TODO: Add support for non-transparent encoders39 */40 41static int ls7a1000_dpi_connector_get_modes(struct drm_connector *conn)42{43	int num;44 45	if (conn->ddc) {46		const struct drm_edid *drm_edid;47 48		drm_edid = drm_edid_read(conn);49		drm_edid_connector_update(conn, drm_edid);50		num = drm_edid_connector_add_modes(conn);51		drm_edid_free(drm_edid);52 53		return num;54	}55 56	num = drm_add_modes_noedid(conn, 1920, 1200);57 58	drm_set_preferred_mode(conn, 1024, 768);59 60	return num;61}62 63static struct drm_encoder *64ls7a1000_dpi_connector_get_best_encoder(struct drm_connector *connector,65					struct drm_atomic_state *state)66{67	struct lsdc_output *output = connector_to_lsdc_output(connector);68 69	return &output->encoder;70}71 72static const struct drm_connector_helper_funcs73ls7a1000_dpi_connector_helpers = {74	.atomic_best_encoder = ls7a1000_dpi_connector_get_best_encoder,75	.get_modes = ls7a1000_dpi_connector_get_modes,76};77 78static enum drm_connector_status79ls7a1000_dpi_connector_detect(struct drm_connector *connector, bool force)80{81	struct i2c_adapter *ddc = connector->ddc;82 83	if (ddc) {84		if (drm_probe_ddc(ddc))85			return connector_status_connected;86 87		return connector_status_disconnected;88	}89 90	return connector_status_unknown;91}92 93static const struct drm_connector_funcs ls7a1000_dpi_connector_funcs = {94	.detect = ls7a1000_dpi_connector_detect,95	.fill_modes = drm_helper_probe_single_connector_modes,96	.destroy = drm_connector_cleanup,97	.reset = drm_atomic_helper_connector_reset,98	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,99	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state100};101 102static void ls7a1000_pipe0_encoder_reset(struct drm_encoder *encoder)103{104	struct drm_device *ddev = encoder->dev;105	struct lsdc_device *ldev = to_lsdc(ddev);106 107	/*108	 * We need this for S3 support, screen will not lightup if don't set109	 * this register correctly.110	 */111	lsdc_wreg32(ldev, LSDC_CRTC0_DVO_CONF_REG,112		    PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN);113}114 115static void ls7a1000_pipe1_encoder_reset(struct drm_encoder *encoder)116{117	struct drm_device *ddev = encoder->dev;118	struct lsdc_device *ldev = to_lsdc(ddev);119 120	/*121	 * We need this for S3 support, screen will not lightup if don't set122	 * this register correctly.123	 */124 125	/* DVO */126	lsdc_wreg32(ldev, LSDC_CRTC1_DVO_CONF_REG,127		    BIT(31) | PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN);128}129 130static const struct drm_encoder_funcs ls7a1000_encoder_funcs[2] = {131	{132		.reset = ls7a1000_pipe0_encoder_reset,133		.destroy = drm_encoder_cleanup,134	},135	{136		.reset = ls7a1000_pipe1_encoder_reset,137		.destroy = drm_encoder_cleanup,138	},139};140 141int ls7a1000_output_init(struct drm_device *ddev,142			 struct lsdc_display_pipe *dispipe,143			 struct i2c_adapter *ddc,144			 unsigned int index)145{146	struct lsdc_output *output = &dispipe->output;147	struct drm_encoder *encoder = &output->encoder;148	struct drm_connector *connector = &output->connector;149	int ret;150 151	ret = drm_encoder_init(ddev, encoder, &ls7a1000_encoder_funcs[index],152			       DRM_MODE_ENCODER_TMDS, "encoder-%u", index);153	if (ret)154		return ret;155 156	encoder->possible_crtcs = BIT(index);157 158	ret = drm_connector_init_with_ddc(ddev, connector,159					  &ls7a1000_dpi_connector_funcs,160					  DRM_MODE_CONNECTOR_DPI, ddc);161	if (ret)162		return ret;163 164	drm_info(ddev, "display pipe-%u has a DVO\n", index);165 166	drm_connector_helper_add(connector, &ls7a1000_dpi_connector_helpers);167 168	drm_connector_attach_encoder(connector, encoder);169 170	connector->polled = DRM_CONNECTOR_POLL_CONNECT |171			    DRM_CONNECTOR_POLL_DISCONNECT;172 173	connector->interlace_allowed = 0;174	connector->doublescan_allowed = 0;175 176	return 0;177}178