18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2018 Loongson Technology Co., Ltd.
38c2ecf20Sopenharmony_ci * Authors:
48c2ecf20Sopenharmony_ci *	Chen Zhu <zhuchen@loongson.cn>
58c2ecf20Sopenharmony_ci *	Yaling Fang <fangyaling@loongson.cn>
68c2ecf20Sopenharmony_ci *	Dandan Zhang <zhangdandan@loongson.cn>
78c2ecf20Sopenharmony_ci *	Huacai Chen <chenhc@lemote.com>
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute  it and/or modify it
98c2ecf20Sopenharmony_ci * under  the terms of  the GNU General  Public License as published by the
108c2ecf20Sopenharmony_ci * Free Software Foundation;  either version 2 of the  License, or (at your
118c2ecf20Sopenharmony_ci * option) any later version.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "loongson_drv.h"
158c2ecf20Sopenharmony_ci#include "loongson_vbios.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define VBIOS_START 0x1000
188c2ecf20Sopenharmony_ci#define VBIOS_SIZE  0x40000
198c2ecf20Sopenharmony_ci#define VBIOS_OFFSET 0x100000
208c2ecf20Sopenharmony_ci#define VBIOS_DESC_OFFSET 0x6000
218c2ecf20Sopenharmony_ci#define VBIOS_TITLE "Loongson-VBIOS"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* VBIOS INFO ADDRESS TABLE */
248c2ecf20Sopenharmony_cistruct acpi_viat_table {
258c2ecf20Sopenharmony_ci	struct acpi_table_header header;
268c2ecf20Sopenharmony_ci	unsigned long vbios_addr;
278c2ecf20Sopenharmony_ci} __packed;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic u32 get_vbios_version(struct loongson_vbios *vbios)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	u32 minor, major, version;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	minor = vbios->version_minor;
348c2ecf20Sopenharmony_ci	major = vbios->version_major;
358c2ecf20Sopenharmony_ci	version = major * 10 + minor;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return version;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic bool parse_vbios_i2c(struct desc_node *this, struct vbios_cmd *cmd)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	bool ret = true;
438c2ecf20Sopenharmony_ci	int i, num, size;
448c2ecf20Sopenharmony_ci	struct vbios_i2c *i2c;
458c2ecf20Sopenharmony_ci	struct vbios_i2c *vbios_i2c = NULL;
468c2ecf20Sopenharmony_ci	struct loongson_i2c *val = (struct loongson_i2c *)cmd->res;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	size = this->desc->size;
498c2ecf20Sopenharmony_ci	vbios_i2c = kzalloc(size, GFP_KERNEL);
508c2ecf20Sopenharmony_ci	if (!vbios_i2c)
518c2ecf20Sopenharmony_ci		return false;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	memset(vbios_i2c, 0xff, size);
548c2ecf20Sopenharmony_ci	memcpy(vbios_i2c, this->data, size);
558c2ecf20Sopenharmony_ci	num = size / sizeof(*vbios_i2c);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	i2c = vbios_i2c;
588c2ecf20Sopenharmony_ci	for (i = 0; (i < num && i < DC_I2C_BUS_MAX); i++) {
598c2ecf20Sopenharmony_ci		val->i2c_id = (u32)i2c->id;
608c2ecf20Sopenharmony_ci		val->use = true;
618c2ecf20Sopenharmony_ci		val++;
628c2ecf20Sopenharmony_ci		i2c++;
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	kfree(vbios_i2c);
668c2ecf20Sopenharmony_ci	return ret;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic bool parse_vbios_crtc(struct desc_node *this, struct vbios_cmd *cmd)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	bool ret = true;
728c2ecf20Sopenharmony_ci	u64 request = (u64)cmd->req;
738c2ecf20Sopenharmony_ci	u32 *val = (u32 *)cmd->res;
748c2ecf20Sopenharmony_ci	struct vbios_crtc crtc;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	memset(&crtc, 0xff, sizeof(crtc));
778c2ecf20Sopenharmony_ci	memcpy(&crtc, this->data, min_t(u32, this->desc->size, sizeof(crtc)));
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	switch (request) {
808c2ecf20Sopenharmony_ci	case VBIOS_CRTC_ID:
818c2ecf20Sopenharmony_ci		*val = crtc.crtc_id;
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci	case VBIOS_CRTC_ENCODER_ID:
848c2ecf20Sopenharmony_ci		*val = crtc.encoder_id;
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci	case VBIOS_CRTC_MAX_FREQ:
878c2ecf20Sopenharmony_ci		*val = crtc.max_freq;
888c2ecf20Sopenharmony_ci		break;
898c2ecf20Sopenharmony_ci	case VBIOS_CRTC_MAX_WIDTH:
908c2ecf20Sopenharmony_ci		*val = crtc.max_width;
918c2ecf20Sopenharmony_ci		break;
928c2ecf20Sopenharmony_ci	case VBIOS_CRTC_MAX_HEIGHT:
938c2ecf20Sopenharmony_ci		*val = crtc.max_height;
948c2ecf20Sopenharmony_ci		break;
958c2ecf20Sopenharmony_ci	case VBIOS_CRTC_IS_VB_TIMING:
968c2ecf20Sopenharmony_ci		*val = crtc.is_vb_timing;
978c2ecf20Sopenharmony_ci		break;
988c2ecf20Sopenharmony_ci	default:
998c2ecf20Sopenharmony_ci		ret = false;
1008c2ecf20Sopenharmony_ci		break;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return ret;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic bool parse_vbios_encoder(struct desc_node *this, struct vbios_cmd *cmd)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	bool ret = true;
1098c2ecf20Sopenharmony_ci	u64 request = (u64)cmd->req;
1108c2ecf20Sopenharmony_ci	u32 *val = (u32 *)cmd->res;
1118c2ecf20Sopenharmony_ci	struct vbios_encoder encoder;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	memset(&encoder, 0xff, sizeof(encoder));
1148c2ecf20Sopenharmony_ci	memcpy(&encoder, this->data,
1158c2ecf20Sopenharmony_ci	       min_t(u32, this->desc->size, sizeof(encoder)));
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	switch (request) {
1188c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_I2C_ID:
1198c2ecf20Sopenharmony_ci		*val = encoder.i2c_id;
1208c2ecf20Sopenharmony_ci		break;
1218c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CONNECTOR_ID:
1228c2ecf20Sopenharmony_ci		*val = encoder.connector_id;
1238c2ecf20Sopenharmony_ci		break;
1248c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_TYPE:
1258c2ecf20Sopenharmony_ci		*val = encoder.type;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CONFIG_TYPE:
1288c2ecf20Sopenharmony_ci		*val = encoder.config_type;
1298c2ecf20Sopenharmony_ci		break;
1308c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CHIP:
1318c2ecf20Sopenharmony_ci		*val = encoder.chip;
1328c2ecf20Sopenharmony_ci		break;
1338c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CHIP_ADDR:
1348c2ecf20Sopenharmony_ci		*val = encoder.chip_addr;
1358c2ecf20Sopenharmony_ci		break;
1368c2ecf20Sopenharmony_ci	default:
1378c2ecf20Sopenharmony_ci		ret = false;
1388c2ecf20Sopenharmony_ci		break;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return ret;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic bool parse_vbios_cfg_encoder(struct desc_node *this,
1458c2ecf20Sopenharmony_ci				    struct vbios_cmd *cmd)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	bool ret = true;
1488c2ecf20Sopenharmony_ci	u64 request = (u64)cmd->req;
1498c2ecf20Sopenharmony_ci	u32 *val = (u32 *)cmd->res;
1508c2ecf20Sopenharmony_ci	struct cfg_encoder *cfg_encoder;
1518c2ecf20Sopenharmony_ci	struct cfg_encoder *cfg;
1528c2ecf20Sopenharmony_ci	struct vbios_cfg_encoder *vbios_cfg_encoder;
1538c2ecf20Sopenharmony_ci	u32 num, size, i = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	vbios_cfg_encoder = (struct vbios_cfg_encoder *)this->data;
1568c2ecf20Sopenharmony_ci	size = sizeof(struct vbios_cfg_encoder);
1578c2ecf20Sopenharmony_ci	num = this->desc->size / size;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	switch (request) {
1608c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CONFIG_PARAM:
1618c2ecf20Sopenharmony_ci		cfg_encoder = (struct cfg_encoder *)kzalloc(
1628c2ecf20Sopenharmony_ci			sizeof(struct cfg_encoder) * num, GFP_KERNEL);
1638c2ecf20Sopenharmony_ci		cfg = cfg_encoder;
1648c2ecf20Sopenharmony_ci		for (i = 0; i < num; i++) {
1658c2ecf20Sopenharmony_ci			cfg->reg_num = vbios_cfg_encoder->reg_num;
1668c2ecf20Sopenharmony_ci			cfg->hdisplay = vbios_cfg_encoder->hdisplay;
1678c2ecf20Sopenharmony_ci			cfg->vdisplay = vbios_cfg_encoder->vdisplay;
1688c2ecf20Sopenharmony_ci			memcpy(&cfg->config_regs,
1698c2ecf20Sopenharmony_ci			       &vbios_cfg_encoder->config_regs,
1708c2ecf20Sopenharmony_ci			       sizeof(struct vbios_conf_reg) * 256);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci			cfg++;
1738c2ecf20Sopenharmony_ci			vbios_cfg_encoder++;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci		cmd->res = (void *)cfg_encoder;
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	case VBIOS_ENCODER_CONFIG_NUM:
1788c2ecf20Sopenharmony_ci		*val = num;
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	default:
1818c2ecf20Sopenharmony_ci		ret = false;
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return ret;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic bool parse_vbios_connector(struct desc_node *this, struct vbios_cmd *cmd)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	bool ret = true;
1918c2ecf20Sopenharmony_ci	u64 request = (u64)cmd->req;
1928c2ecf20Sopenharmony_ci	u32 *val = (u32 *)cmd->res;
1938c2ecf20Sopenharmony_ci	struct vbios_connector connector;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	memset(&connector, 0xff, sizeof(connector));
1968c2ecf20Sopenharmony_ci	memcpy(&connector, this->data,
1978c2ecf20Sopenharmony_ci	       min_t(u32, this->desc->size, sizeof(connector)));
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	switch (request) {
2008c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_I2C_ID:
2018c2ecf20Sopenharmony_ci		*val = connector.i2c_id;
2028c2ecf20Sopenharmony_ci		break;
2038c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_INTERNAL_EDID:
2048c2ecf20Sopenharmony_ci		memcpy((u8 *)(ulong)val, connector.internal_edid,
2058c2ecf20Sopenharmony_ci		       EDID_LENGTH * 2);
2068c2ecf20Sopenharmony_ci		break;
2078c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_TYPE:
2088c2ecf20Sopenharmony_ci		*val = connector.type;
2098c2ecf20Sopenharmony_ci		break;
2108c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_HOTPLUG:
2118c2ecf20Sopenharmony_ci		*val = connector.hotplug;
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_EDID_METHOD:
2148c2ecf20Sopenharmony_ci		*val = connector.edid_method;
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_IRQ_GPIO:
2178c2ecf20Sopenharmony_ci		*val = connector.irq_gpio;
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci	case VBIOS_CONNECTOR_IRQ_PLACEMENT:
2208c2ecf20Sopenharmony_ci		*val = connector.gpio_placement;
2218c2ecf20Sopenharmony_ci		break;
2228c2ecf20Sopenharmony_ci	default:
2238c2ecf20Sopenharmony_ci		ret = false;
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return ret;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic bool parse_vbios_backlight(struct desc_node *this, struct vbios_cmd *cmd)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	return 0;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic bool parse_vbios_pwm(struct desc_node *this, struct vbios_cmd *cmd)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	bool ret = true;
2388c2ecf20Sopenharmony_ci	u64 request = (u64)cmd->req;
2398c2ecf20Sopenharmony_ci	u32 *val = (u32 *)cmd->res;
2408c2ecf20Sopenharmony_ci	struct vbios_pwm *pwm = (struct vbios_pwm *)this->data;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	switch (request) {
2438c2ecf20Sopenharmony_ci	case VBIOS_PWM_ID:
2448c2ecf20Sopenharmony_ci		*val = pwm->pwm;
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	case VBIOS_PWM_PERIOD:
2478c2ecf20Sopenharmony_ci		*val = pwm->peroid;
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case VBIOS_PWM_POLARITY:
2508c2ecf20Sopenharmony_ci		*val = pwm->polarity;
2518c2ecf20Sopenharmony_ci		break;
2528c2ecf20Sopenharmony_ci	default:
2538c2ecf20Sopenharmony_ci		ret = false;
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return ret;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic bool parse_vbios_header(struct desc_node *this, struct vbios_cmd *cmd)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	return true;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic bool parse_vbios_default(struct desc_node *this, struct vbios_cmd *cmd)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct vbios_desc *vb_desc;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	vb_desc = this->desc;
2708c2ecf20Sopenharmony_ci	DRM_WARN("Current descriptor[T-%d][V-%d] cannot be interprete.\n",
2718c2ecf20Sopenharmony_ci		 vb_desc->type, vb_desc->ver);
2728c2ecf20Sopenharmony_ci	return false;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#define FUNC(t, v, f)                                                          \
2768c2ecf20Sopenharmony_ci	{                                                                      \
2778c2ecf20Sopenharmony_ci		.type = t, .ver = v, .func = f,                                \
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic struct desc_func tables[] = {
2818c2ecf20Sopenharmony_ci	FUNC(desc_header, ver_v1, parse_vbios_header),
2828c2ecf20Sopenharmony_ci	FUNC(desc_i2c, ver_v1, parse_vbios_i2c),
2838c2ecf20Sopenharmony_ci	FUNC(desc_crtc, ver_v1, parse_vbios_crtc),
2848c2ecf20Sopenharmony_ci	FUNC(desc_encoder, ver_v1, parse_vbios_encoder),
2858c2ecf20Sopenharmony_ci	FUNC(desc_connector, ver_v1, parse_vbios_connector),
2868c2ecf20Sopenharmony_ci	FUNC(desc_cfg_encoder, ver_v1, parse_vbios_cfg_encoder),
2878c2ecf20Sopenharmony_ci	FUNC(desc_backlight, ver_v1, parse_vbios_backlight),
2888c2ecf20Sopenharmony_ci	FUNC(desc_pwm, ver_v1, parse_vbios_pwm),
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic inline parse_func *get_parse_func(struct vbios_desc *vb_desc)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	int i;
2948c2ecf20Sopenharmony_ci	u32 type = vb_desc->type;
2958c2ecf20Sopenharmony_ci	u32 ver = vb_desc->ver;
2968c2ecf20Sopenharmony_ci	parse_func *func = parse_vbios_default;
2978c2ecf20Sopenharmony_ci	u32 tt_num = ARRAY_SIZE(tables);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	for (i = 0; i < tt_num; i++) {
3008c2ecf20Sopenharmony_ci		if ((tables[i].ver == ver) && (tables[i].type == type)) {
3018c2ecf20Sopenharmony_ci			func = tables[i].func;
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return func;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic inline u32 insert_desc_list(struct loongson_drm_device *ldev,
3108c2ecf20Sopenharmony_ci				   struct vbios_desc *vb_desc)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct desc_node *node;
3138c2ecf20Sopenharmony_ci	parse_func *func = NULL;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	WARN_ON(!ldev || !vb_desc);
3168c2ecf20Sopenharmony_ci	node = (struct desc_node *)kzalloc(sizeof(*node), GFP_KERNEL);
3178c2ecf20Sopenharmony_ci	if (!node)
3188c2ecf20Sopenharmony_ci		return -ENOMEM;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	func = get_parse_func(vb_desc);
3218c2ecf20Sopenharmony_ci	node->parse = func;
3228c2ecf20Sopenharmony_ci	node->desc = (void *)vb_desc;
3238c2ecf20Sopenharmony_ci	node->data = ((u8 *)ldev->vbios + vb_desc->offset);
3248c2ecf20Sopenharmony_ci	list_add_tail(&node->head, &ldev->desc_list);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic inline void free_desc_list(struct loongson_drm_device *ldev)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct desc_node *node, *tmp;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	list_for_each_entry_safe (node, tmp, &ldev->desc_list, head) {
3348c2ecf20Sopenharmony_ci		list_del(&node->head);
3358c2ecf20Sopenharmony_ci		kfree(node);
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci#define DESC_LIST_MAX 1024
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic u32 parse_vbios_desc(struct loongson_drm_device *ldev)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	u32 i, ret = 0;
3448c2ecf20Sopenharmony_ci	struct vbios_desc *desc;
3458c2ecf20Sopenharmony_ci	enum desc_type type = 0;
3468c2ecf20Sopenharmony_ci	u8 *vbios = (u8 *)ldev->vbios;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	WARN_ON(!vbios);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	desc = (struct vbios_desc *)(vbios + VBIOS_DESC_OFFSET);
3518c2ecf20Sopenharmony_ci	for (i = 0; i < DESC_LIST_MAX; i++) {
3528c2ecf20Sopenharmony_ci		type = desc->type;
3538c2ecf20Sopenharmony_ci		if (type == desc_max)
3548c2ecf20Sopenharmony_ci			break;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci		ret = insert_desc_list(ldev, desc);
3578c2ecf20Sopenharmony_ci		if (ret)
3588c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Parse T-%d V-%d failed[%d]\n", desc->ver,
3598c2ecf20Sopenharmony_ci				      desc->type, ret);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		desc++;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return ret;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic inline struct desc_node *get_desc_node(struct loongson_drm_device *ldev,
3688c2ecf20Sopenharmony_ci					      u16 type, u8 index)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct desc_node *node, *tmp;
3718c2ecf20Sopenharmony_ci	struct vbios_desc *vb_desc;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	list_for_each_entry_safe (node, tmp, &ldev->desc_list, head) {
3748c2ecf20Sopenharmony_ci		vb_desc = node->desc;
3758c2ecf20Sopenharmony_ci		if (vb_desc->type == type && vb_desc->index == index)
3768c2ecf20Sopenharmony_ci			return node;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return NULL;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic bool vbios_get_data(struct loongson_drm_device *ldev, struct vbios_cmd *cmd)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct desc_node *node;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	WARN_ON(!cmd);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	node = get_desc_node(ldev, cmd->type, cmd->index);
3898c2ecf20Sopenharmony_ci	if (node && node->parse)
3908c2ecf20Sopenharmony_ci		return node->parse(node, cmd);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("Failed to get node(%d,%d)\n", cmd->type, cmd->index);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return false;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciu32 get_connector_type(struct loongson_drm_device *ldev, u32 index)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	u32 type = -1;
4008c2ecf20Sopenharmony_ci	bool ret = false;
4018c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4048c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4058c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_TYPE;
4068c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&type;
4078c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4088c2ecf20Sopenharmony_ci	if (!ret)
4098c2ecf20Sopenharmony_ci		type = -1;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return type;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciu16 get_connector_i2cid(struct loongson_drm_device *ldev, u32 index)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	u16 i2c_id = -1;
4178c2ecf20Sopenharmony_ci	bool ret = false;
4188c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4218c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4228c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_I2C_ID;
4238c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&i2c_id;
4248c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4258c2ecf20Sopenharmony_ci	if (!ret)
4268c2ecf20Sopenharmony_ci		i2c_id = -1;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return i2c_id;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciu32 get_connector_irq_gpio(struct loongson_drm_device *ldev, u32 index)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	int ret;
4348c2ecf20Sopenharmony_ci	u32 irq_gpio;
4358c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4388c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4398c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_IRQ_GPIO;
4408c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&irq_gpio;
4418c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4428c2ecf20Sopenharmony_ci	if (!ret)
4438c2ecf20Sopenharmony_ci		return -1;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	return irq_gpio;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cienum gpio_placement get_connector_gpio_placement(struct loongson_drm_device *ldev,
4498c2ecf20Sopenharmony_ci						 u32 index)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	int ret;
4528c2ecf20Sopenharmony_ci	enum gpio_placement irq_placement;
4538c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4568c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4578c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_IRQ_PLACEMENT;
4588c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&irq_placement;
4598c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4608c2ecf20Sopenharmony_ci	if (!ret)
4618c2ecf20Sopenharmony_ci		return -1;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return irq_placement;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ciu16 get_hotplug_mode(struct loongson_drm_device *ldev, u32 index)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	u16 mode = -1;
4698c2ecf20Sopenharmony_ci	bool ret = false;
4708c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4738c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4748c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_HOTPLUG;
4758c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&mode;
4768c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4778c2ecf20Sopenharmony_ci	if (!ret)
4788c2ecf20Sopenharmony_ci		mode = -1;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	return mode;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ciu16 get_edid_method(struct loongson_drm_device *ldev, u32 index)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	bool ret = false;
4868c2ecf20Sopenharmony_ci	u16 method = via_null;
4878c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
4908c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
4918c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_EDID_METHOD;
4928c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&method;
4938c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
4948c2ecf20Sopenharmony_ci	if (!ret)
4958c2ecf20Sopenharmony_ci		method = via_null;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return method;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ciu8 *get_vbios_edid(struct loongson_drm_device *ldev, u32 index)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	u8 *edid = NULL;
5038c2ecf20Sopenharmony_ci	bool ret = false;
5048c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	edid = kzalloc(sizeof(u8) * EDID_LENGTH * 2, GFP_KERNEL);
5078c2ecf20Sopenharmony_ci	if (!edid)
5088c2ecf20Sopenharmony_ci		return edid;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5118c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_connector;
5128c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CONNECTOR_INTERNAL_EDID;
5138c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)edid;
5148c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
5158c2ecf20Sopenharmony_ci	if (!ret)
5168c2ecf20Sopenharmony_ci		return NULL;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return edid;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciu32 get_vbios_pwm(struct loongson_drm_device *ldev, u32 index, u16 request)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	u32 value = -1;
5248c2ecf20Sopenharmony_ci	bool ret = false;
5258c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5288c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_pwm;
5298c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)request;
5308c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&value;
5318c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
5328c2ecf20Sopenharmony_ci	if (!ret)
5338c2ecf20Sopenharmony_ci		value = 0xffffffff;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return value;
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ciu32 get_crtc_id(struct loongson_drm_device *ldev, u32 index)
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	u32 crtc_id = 0;
5418c2ecf20Sopenharmony_ci	bool ret = false;
5428c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5458c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
5468c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_ID;
5478c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&crtc_id;
5488c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
5498c2ecf20Sopenharmony_ci	if (!ret)
5508c2ecf20Sopenharmony_ci		crtc_id = 0;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return crtc_id;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ciu32 get_crtc_max_freq(struct loongson_drm_device *ldev, u32 index)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	bool ret = false;
5588c2ecf20Sopenharmony_ci	u32 max_freq = 0;
5598c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5628c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
5638c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_MAX_FREQ;
5648c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&max_freq;
5658c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
5668c2ecf20Sopenharmony_ci	if (!ret)
5678c2ecf20Sopenharmony_ci		max_freq = 0;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return max_freq;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ciu32 get_crtc_max_width(struct loongson_drm_device *ldev, u32 index)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	bool ret = false;
5758c2ecf20Sopenharmony_ci	u32 max_width = 0;
5768c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5798c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
5808c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_MAX_WIDTH;
5818c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&max_width;
5828c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
5838c2ecf20Sopenharmony_ci	if (!ret)
5848c2ecf20Sopenharmony_ci		max_width = LOONGSON_MAX_FB_WIDTH;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return max_width;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ciu32 get_crtc_max_height(struct loongson_drm_device *ldev, u32 index)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	bool ret = false;
5928c2ecf20Sopenharmony_ci	u32 max_height = 0;
5938c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
5968c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
5978c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_MAX_HEIGHT;
5988c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&max_height;
5998c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6008c2ecf20Sopenharmony_ci	if (!ret)
6018c2ecf20Sopenharmony_ci		max_height = LOONGSON_MAX_FB_HEIGHT;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	return max_height;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ciu32 get_crtc_encoder_id(struct loongson_drm_device *ldev, u32 index)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	bool ret = false;
6098c2ecf20Sopenharmony_ci	u32 encoder_id = 0;
6108c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
6138c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
6148c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_ENCODER_ID;
6158c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&encoder_id;
6168c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6178c2ecf20Sopenharmony_ci	if (!ret)
6188c2ecf20Sopenharmony_ci		encoder_id = 0;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return encoder_id;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cibool get_crtc_is_vb_timing(struct loongson_drm_device *ldev, u32 index)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	bool ret = false;
6268c2ecf20Sopenharmony_ci	bool vb_timing = false;
6278c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
6308c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_crtc;
6318c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_CRTC_IS_VB_TIMING;
6328c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&vb_timing;
6338c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6348c2ecf20Sopenharmony_ci	if (!ret)
6358c2ecf20Sopenharmony_ci		vb_timing = false;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	return vb_timing;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistruct crtc_timing *get_crtc_timing(struct loongson_drm_device *ldev, u32 index)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	return NULL;
6438c2ecf20Sopenharmony_ci}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ciu32 get_encoder_connector_id(struct loongson_drm_device *ldev, u32 index)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	bool ret = false;
6488c2ecf20Sopenharmony_ci	u32 connector_id = 0;
6498c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
6528c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
6538c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CONNECTOR_ID;
6548c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&connector_id;
6558c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6568c2ecf20Sopenharmony_ci	if (!ret)
6578c2ecf20Sopenharmony_ci		connector_id = 0;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	return connector_id;
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ciu32 get_encoder_i2c_id(struct loongson_drm_device *ldev, u32 index)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	u32 i2c_id = 0;
6658c2ecf20Sopenharmony_ci	bool ret = false;
6668c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
6698c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
6708c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_I2C_ID;
6718c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&i2c_id;
6728c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6738c2ecf20Sopenharmony_ci	if (!ret)
6748c2ecf20Sopenharmony_ci		i2c_id = 0;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	return i2c_id;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cistruct cfg_encoder *get_encoder_config(struct loongson_drm_device *ldev, u32 index)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	bool ret = false;
6828c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6838c2ecf20Sopenharmony_ci	struct cfg_encoder *encoder_config = NULL;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
6868c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_cfg_encoder;
6878c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CONFIG_PARAM;
6888c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
6898c2ecf20Sopenharmony_ci	if (ret)
6908c2ecf20Sopenharmony_ci		encoder_config = (struct cfg_encoder *)vbt_cmd.res;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	return encoder_config;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ciu32 get_encoder_cfg_num(struct loongson_drm_device *ldev, u32 index)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
6988c2ecf20Sopenharmony_ci	bool ret = false;
6998c2ecf20Sopenharmony_ci	u32 cfg_num = 0;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
7028c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_cfg_encoder;
7038c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CONFIG_NUM;
7048c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&cfg_num;
7058c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7068c2ecf20Sopenharmony_ci	if (!ret)
7078c2ecf20Sopenharmony_ci		cfg_num = 0;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return cfg_num;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cienum encoder_config get_encoder_config_type(struct loongson_drm_device *ldev,
7138c2ecf20Sopenharmony_ci					    u32 index)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	bool ret = false;
7168c2ecf20Sopenharmony_ci	enum encoder_config config_type = encoder_bios_config;
7178c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
7208c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
7218c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CONFIG_TYPE;
7228c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&config_type;
7238c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7248c2ecf20Sopenharmony_ci	if (!ret)
7258c2ecf20Sopenharmony_ci		config_type = encoder_bios_config;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	return config_type;
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cienum encoder_object get_encoder_chip(struct loongson_drm_device *ldev, u32 index)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	int ret;
7338c2ecf20Sopenharmony_ci	enum encoder_object chip;
7348c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
7378c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
7388c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CHIP;
7398c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&chip;
7408c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7418c2ecf20Sopenharmony_ci	if (!ret)
7428c2ecf20Sopenharmony_ci		return Unknown;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	return chip;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ciu8 get_encoder_chip_addr(struct loongson_drm_device *ldev, u32 index)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	int ret;
7508c2ecf20Sopenharmony_ci	u8 chip_addr;
7518c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
7548c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
7558c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_CHIP_ADDR;
7568c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&chip_addr;
7578c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7588c2ecf20Sopenharmony_ci	if (!ret)
7598c2ecf20Sopenharmony_ci		return Unknown;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	return chip_addr;
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_cienum encoder_type get_encoder_type(struct loongson_drm_device *ldev, u32 index)
7658c2ecf20Sopenharmony_ci{
7668c2ecf20Sopenharmony_ci	bool ret = false;
7678c2ecf20Sopenharmony_ci	enum encoder_type type = encoder_dac;
7688c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	vbt_cmd.index = index;
7718c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_encoder;
7728c2ecf20Sopenharmony_ci	vbt_cmd.req = (void *)(ulong)VBIOS_ENCODER_TYPE;
7738c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)(ulong)&type;
7748c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7758c2ecf20Sopenharmony_ci	if (!ret)
7768c2ecf20Sopenharmony_ci		type = encoder_dac;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	return type;
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cibool get_loongson_i2c(struct loongson_drm_device *ldev)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	bool ret = false;
7848c2ecf20Sopenharmony_ci	struct vbios_cmd vbt_cmd;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	vbt_cmd.index = 0;
7878c2ecf20Sopenharmony_ci	vbt_cmd.type = desc_i2c;
7888c2ecf20Sopenharmony_ci	vbt_cmd.res = (void *)&ldev->i2c_bus;
7898c2ecf20Sopenharmony_ci	ret = vbios_get_data(ldev, &vbt_cmd);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (!ret) {
7928c2ecf20Sopenharmony_ci		ldev->i2c_bus[0].use = true;
7938c2ecf20Sopenharmony_ci		ldev->i2c_bus[1].use = true;
7948c2ecf20Sopenharmony_ci	}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	return true;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic void *get_vbios_from_acpi(struct loongson_drm_device *ldev)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	void *vbios = NULL;
8028c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
8038c2ecf20Sopenharmony_ci	struct acpi_viat_table *viat;
8048c2ecf20Sopenharmony_ci	struct acpi_table_header *hdr;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (!ACPI_SUCCESS(acpi_get_table("VIAT", 1, &hdr)))
8078c2ecf20Sopenharmony_ci		return NULL;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (hdr->length != sizeof(struct acpi_viat_table)) {
8108c2ecf20Sopenharmony_ci		DRM_WARN("ACPI VIAT table present but broken (length error)\n");
8118c2ecf20Sopenharmony_ci		return NULL;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	vbios = kmalloc(VBIOS_SIZE, GFP_KERNEL);
8158c2ecf20Sopenharmony_ci	if (!vbios)
8168c2ecf20Sopenharmony_ci		return NULL;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	viat = (struct acpi_viat_table *)hdr;
8198c2ecf20Sopenharmony_ci	memcpy(vbios, phys_to_virt(viat->vbios_addr), VBIOS_SIZE);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	DRM_INFO("Get VBIOS from ACPI success!\n");
8228c2ecf20Sopenharmony_ci#endif
8238c2ecf20Sopenharmony_ci	return vbios;
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic void *get_vbios_from_vram(struct loongson_drm_device *ldev)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	void *bios, *vbios = NULL;
8298c2ecf20Sopenharmony_ci	u64 vram_base = pci_resource_start(ldev->gpu_pdev, 2);
8308c2ecf20Sopenharmony_ci	u64 vram_size = pci_resource_len(ldev->gpu_pdev, 2);
8318c2ecf20Sopenharmony_ci	u64 vbios_addr = vram_base + vram_size - VBIOS_OFFSET;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	bios = ioremap(vbios_addr, VBIOS_SIZE);
8348c2ecf20Sopenharmony_ci	if (!bios)
8358c2ecf20Sopenharmony_ci		return NULL;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	vbios = kmalloc(VBIOS_SIZE, GFP_KERNEL);
8388c2ecf20Sopenharmony_ci	if (!vbios)
8398c2ecf20Sopenharmony_ci		return NULL;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	memcpy(vbios, bios, VBIOS_SIZE);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	iounmap(bios);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (memcmp(vbios, VBIOS_TITLE, strlen(VBIOS_TITLE))) {
8468c2ecf20Sopenharmony_ci		kfree(vbios);
8478c2ecf20Sopenharmony_ci		return NULL;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	DRM_INFO("Get VBIOS from VRAM success!\n");
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	return vbios;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cibool loongson_vbios_init(struct loongson_drm_device *ldev)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	void *vbios = NULL;
8588c2ecf20Sopenharmony_ci	struct loongson_vbios *header;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	vbios = get_vbios_from_vram(ldev);
8618c2ecf20Sopenharmony_ci	if (vbios)
8628c2ecf20Sopenharmony_ci		goto success;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	vbios = get_vbios_from_acpi(ldev);
8658c2ecf20Sopenharmony_ci	if (vbios)
8668c2ecf20Sopenharmony_ci		goto success;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	vbios = kzalloc(256 * 1024, GFP_KERNEL);
8698c2ecf20Sopenharmony_ci	if (!vbios)
8708c2ecf20Sopenharmony_ci		return false;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	header = vbios;
8738c2ecf20Sopenharmony_ci	header->crtc_num = 2;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cisuccess:
8768c2ecf20Sopenharmony_ci	header = ldev->vbios = vbios;
8778c2ecf20Sopenharmony_ci	ldev->num_crtc = header->crtc_num;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	DRM_INFO("Loongson VBIOS version %d.%d\n", header->version_major,
8808c2ecf20Sopenharmony_ci		 header->version_minor);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ldev->desc_list);
8838c2ecf20Sopenharmony_ci	parse_vbios_desc(ldev);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	return true;
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_civoid loongson_vbios_exit(struct loongson_drm_device *ldev)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	free_desc_list(ldev);
8918c2ecf20Sopenharmony_ci	kfree(ldev->vbios);
8928c2ecf20Sopenharmony_ci}
893