brintos

brintos / linux-shallow public Read only

0
0
Text · 14.4 KiB · e4c636f Raw
617 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/delay.h>4#include <linux/firmware.h>5#include <linux/module.h>6 7#include <drm/drm_atomic_state_helper.h>8#include <drm/drm_edid.h>9#include <drm/drm_modeset_helper_vtables.h>10#include <drm/drm_probe_helper.h>11 12#include "ast_drv.h"13 14MODULE_FIRMWARE("ast_dp501_fw.bin");15 16static void ast_release_firmware(void *data)17{18	struct ast_device *ast = data;19 20	release_firmware(ast->dp501_fw);21	ast->dp501_fw = NULL;22}23 24static int ast_load_dp501_microcode(struct drm_device *dev)25{26	struct ast_device *ast = to_ast_device(dev);27	int ret;28 29	ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);30	if (ret)31		return ret;32 33	return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast);34}35 36static void send_ack(struct ast_device *ast)37{38	u8 sendack;39	sendack = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, 0xff);40	sendack |= 0x80;41	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, 0x00, sendack);42}43 44static void send_nack(struct ast_device *ast)45{46	u8 sendack;47	sendack = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, 0xff);48	sendack &= ~0x80;49	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, 0x00, sendack);50}51 52static bool wait_ack(struct ast_device *ast)53{54	u8 waitack;55	u32 retry = 0;56	do {57		waitack = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd2, 0xff);58		waitack &= 0x80;59		udelay(100);60	} while ((!waitack) && (retry++ < 1000));61 62	if (retry < 1000)63		return true;64	else65		return false;66}67 68static bool wait_nack(struct ast_device *ast)69{70	u8 waitack;71	u32 retry = 0;72	do {73		waitack = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd2, 0xff);74		waitack &= 0x80;75		udelay(100);76	} while ((waitack) && (retry++ < 1000));77 78	if (retry < 1000)79		return true;80	else81		return false;82}83 84static void set_cmd_trigger(struct ast_device *ast)85{86	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, ~0x40, 0x40);87}88 89static void clear_cmd_trigger(struct ast_device *ast)90{91	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9b, ~0x40, 0x00);92}93 94#if 095static bool wait_fw_ready(struct ast_device *ast)96{97	u8 waitready;98	u32 retry = 0;99	do {100		waitready = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd2, 0xff);101		waitready &= 0x40;102		udelay(100);103	} while ((!waitready) && (retry++ < 1000));104 105	if (retry < 1000)106		return true;107	else108		return false;109}110#endif111 112static bool ast_write_cmd(struct drm_device *dev, u8 data)113{114	struct ast_device *ast = to_ast_device(dev);115	int retry = 0;116	if (wait_nack(ast)) {117		send_nack(ast);118		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9a, 0x00, data);119		send_ack(ast);120		set_cmd_trigger(ast);121		do {122			if (wait_ack(ast)) {123				clear_cmd_trigger(ast);124				send_nack(ast);125				return true;126			}127		} while (retry++ < 100);128	}129	clear_cmd_trigger(ast);130	send_nack(ast);131	return false;132}133 134static bool ast_write_data(struct drm_device *dev, u8 data)135{136	struct ast_device *ast = to_ast_device(dev);137 138	if (wait_nack(ast)) {139		send_nack(ast);140		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9a, 0x00, data);141		send_ack(ast);142		if (wait_ack(ast)) {143			send_nack(ast);144			return true;145		}146	}147	send_nack(ast);148	return false;149}150 151#if 0152static bool ast_read_data(struct drm_device *dev, u8 *data)153{154	struct ast_device *ast = to_ast_device(dev);155	u8 tmp;156 157	*data = 0;158 159	if (wait_ack(ast) == false)160		return false;161	tmp = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd3, 0xff);162	*data = tmp;163	if (wait_nack(ast) == false) {164		send_nack(ast);165		return false;166	}167	send_nack(ast);168	return true;169}170 171static void clear_cmd(struct ast_device *ast)172{173	send_nack(ast);174	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9a, 0x00, 0x00);175}176#endif177 178static void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)179{180	ast_write_cmd(dev, 0x40);181	ast_write_data(dev, mode);182 183	msleep(10);184}185 186static u32 get_fw_base(struct ast_device *ast)187{188	return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;189}190 191bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)192{193	struct ast_device *ast = to_ast_device(dev);194	u32 i, data;195	u32 boot_address;196 197	if (ast->config_mode != ast_use_p2a)198		return false;199 200	data = ast_mindwm(ast, 0x1e6e2100) & 0x01;201	if (data) {202		boot_address = get_fw_base(ast);203		for (i = 0; i < size; i += 4)204			*(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);205		return true;206	}207	return false;208}209 210static bool ast_launch_m68k(struct drm_device *dev)211{212	struct ast_device *ast = to_ast_device(dev);213	u32 i, data, len = 0;214	u32 boot_address;215	u8 *fw_addr = NULL;216	u8 jreg;217 218	if (ast->config_mode != ast_use_p2a)219		return false;220 221	data = ast_mindwm(ast, 0x1e6e2100) & 0x01;222	if (!data) {223 224		if (ast->dp501_fw_addr) {225			fw_addr = ast->dp501_fw_addr;226			len = 32*1024;227		} else {228			if (!ast->dp501_fw &&229			    ast_load_dp501_microcode(dev) < 0)230				return false;231 232			fw_addr = (u8 *)ast->dp501_fw->data;233			len = ast->dp501_fw->size;234		}235		/* Get BootAddress */236		ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);237		data = ast_mindwm(ast, 0x1e6e0004);238		switch (data & 0x03) {239		case 0:240			boot_address = 0x44000000;241			break;242		default:243		case 1:244			boot_address = 0x48000000;245			break;246		case 2:247			boot_address = 0x50000000;248			break;249		case 3:250			boot_address = 0x60000000;251			break;252		}253		boot_address -= 0x200000; /* -2MB */254 255		/* copy image to buffer */256		for (i = 0; i < len; i += 4) {257			data = *(u32 *)(fw_addr + i);258			ast_moutdwm(ast, boot_address + i, data);259		}260 261		/* Init SCU */262		ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);263 264		/* Launch FW */265		ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);266		ast_moutdwm(ast, 0x1e6e2100, 1);267 268		/* Update Scratch */269		data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff;		/* D[11:9] = 100b: UEFI handling */270		data |= 0x800;271		ast_moutdwm(ast, 0x1e6e2040, data);272 273		jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0x99, 0xfc); /* D[1:0]: Reserved Video Buffer */274		jreg |= 0x02;275		ast_set_index_reg(ast, AST_IO_VGACRI, 0x99, jreg);276	}277	return true;278}279 280static bool ast_dp501_is_connected(struct ast_device *ast)281{282	u32 boot_address, offset, data;283 284	if (ast->config_mode == ast_use_p2a) {285		boot_address = get_fw_base(ast);286 287		/* validate FW version */288		offset = AST_DP501_GBL_VERSION;289		data = ast_mindwm(ast, boot_address + offset);290		if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1)291			return false;292 293		/* validate PnP Monitor */294		offset = AST_DP501_PNPMONITOR;295		data = ast_mindwm(ast, boot_address + offset);296		if (!(data & AST_DP501_PNP_CONNECTED))297			return false;298	} else {299		if (!ast->dp501_fw_buf)300			return false;301 302		/* dummy read */303		offset = 0x0000;304		data = readl(ast->dp501_fw_buf + offset);305 306		/* validate FW version */307		offset = AST_DP501_GBL_VERSION;308		data = readl(ast->dp501_fw_buf + offset);309		if ((data & AST_DP501_FW_VERSION_MASK) != AST_DP501_FW_VERSION_1)310			return false;311 312		/* validate PnP Monitor */313		offset = AST_DP501_PNPMONITOR;314		data = readl(ast->dp501_fw_buf + offset);315		if (!(data & AST_DP501_PNP_CONNECTED))316			return false;317	}318	return true;319}320 321static int ast_dp512_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len)322{323	struct ast_device *ast = data;324	size_t rdlen = round_up(len, 4);325	u32 i, boot_address, offset, ediddata;326 327	if (block > (512 / EDID_LENGTH))328		return -EIO;329 330	offset = AST_DP501_EDID_DATA + block * EDID_LENGTH;331 332	if (ast->config_mode == ast_use_p2a) {333		boot_address = get_fw_base(ast);334 335		for (i = 0; i < rdlen; i += 4) {336			ediddata = ast_mindwm(ast, boot_address + offset + i);337			memcpy(buf, &ediddata, min((len - i), 4));338			buf += 4;339		}340	} else {341		for (i = 0; i < rdlen; i += 4) {342			ediddata = readl(ast->dp501_fw_buf + offset + i);343			memcpy(buf, &ediddata, min((len - i), 4));344			buf += 4;345		}346	}347 348	return true;349}350 351static bool ast_init_dvo(struct drm_device *dev)352{353	struct ast_device *ast = to_ast_device(dev);354	u8 jreg;355	u32 data;356	ast_write32(ast, 0xf004, 0x1e6e0000);357	ast_write32(ast, 0xf000, 0x1);358	ast_write32(ast, 0x12000, 0x1688a8a8);359 360	jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff);361	if (!(jreg & 0x80)) {362		/* Init SCU DVO Settings */363		data = ast_read32(ast, 0x12008);364		/* delay phase */365		data &= 0xfffff8ff;366		data |= 0x00000500;367		ast_write32(ast, 0x12008, data);368 369		if (IS_AST_GEN4(ast)) {370			data = ast_read32(ast, 0x12084);371			/* multi-pins for DVO single-edge */372			data |= 0xfffe0000;373			ast_write32(ast, 0x12084, data);374 375			data = ast_read32(ast, 0x12088);376			/* multi-pins for DVO single-edge */377			data |= 0x000fffff;378			ast_write32(ast, 0x12088, data);379 380			data = ast_read32(ast, 0x12090);381			/* multi-pins for DVO single-edge */382			data &= 0xffffffcf;383			data |= 0x00000020;384			ast_write32(ast, 0x12090, data);385		} else { /* AST GEN5+ */386			data = ast_read32(ast, 0x12088);387			/* multi-pins for DVO single-edge */388			data |= 0x30000000;389			ast_write32(ast, 0x12088, data);390 391			data = ast_read32(ast, 0x1208c);392			/* multi-pins for DVO single-edge */393			data |= 0x000000cf;394			ast_write32(ast, 0x1208c, data);395 396			data = ast_read32(ast, 0x120a4);397			/* multi-pins for DVO single-edge */398			data |= 0xffff0000;399			ast_write32(ast, 0x120a4, data);400 401			data = ast_read32(ast, 0x120a8);402			/* multi-pins for DVO single-edge */403			data |= 0x0000000f;404			ast_write32(ast, 0x120a8, data);405 406			data = ast_read32(ast, 0x12094);407			/* multi-pins for DVO single-edge */408			data |= 0x00000002;409			ast_write32(ast, 0x12094, data);410		}411	}412 413	/* Force to DVO */414	data = ast_read32(ast, 0x1202c);415	data &= 0xfffbffff;416	ast_write32(ast, 0x1202c, data);417 418	/* Init VGA DVO Settings */419	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80);420	return true;421}422 423 424static void ast_init_analog(struct drm_device *dev)425{426	struct ast_device *ast = to_ast_device(dev);427	u32 data;428 429	/*430	 * Set DAC source to VGA mode in SCU2C via the P2A431	 * bridge. First configure the P2U to target the SCU432	 * in case it isn't at this stage.433	 */434	ast_write32(ast, 0xf004, 0x1e6e0000);435	ast_write32(ast, 0xf000, 0x1);436 437	/* Then unlock the SCU with the magic password */438	ast_write32(ast, 0x12000, 0x1688a8a8);439	ast_write32(ast, 0x12000, 0x1688a8a8);440	ast_write32(ast, 0x12000, 0x1688a8a8);441 442	/* Finally, clear bits [17:16] of SCU2c */443	data = ast_read32(ast, 0x1202c);444	data &= 0xfffcffff;445	ast_write32(ast, 0, data);446 447	/* Disable DVO */448	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00);449}450 451void ast_init_3rdtx(struct drm_device *dev)452{453	struct ast_device *ast = to_ast_device(dev);454	u8 jreg;455 456	if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast)) {457		jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff);458		switch (jreg & 0x0e) {459		case 0x04:460			ast_init_dvo(dev);461			break;462		case 0x08:463			ast_launch_m68k(dev);464			break;465		case 0x0c:466			ast_init_dvo(dev);467			break;468		default:469			if (ast->tx_chip_types & BIT(AST_TX_SIL164))470				ast_init_dvo(dev);471			else472				ast_init_analog(dev);473		}474	}475}476 477/*478 * Encoder479 */480 481static const struct drm_encoder_funcs ast_dp501_encoder_funcs = {482	.destroy = drm_encoder_cleanup,483};484 485static void ast_dp501_encoder_helper_atomic_enable(struct drm_encoder *encoder,486						   struct drm_atomic_state *state)487{488	struct drm_device *dev = encoder->dev;489 490	ast_set_dp501_video_output(dev, 1);491}492 493static void ast_dp501_encoder_helper_atomic_disable(struct drm_encoder *encoder,494						    struct drm_atomic_state *state)495{496	struct drm_device *dev = encoder->dev;497 498	ast_set_dp501_video_output(dev, 0);499}500 501static const struct drm_encoder_helper_funcs ast_dp501_encoder_helper_funcs = {502	.atomic_enable = ast_dp501_encoder_helper_atomic_enable,503	.atomic_disable = ast_dp501_encoder_helper_atomic_disable,504};505 506/*507 * Connector508 */509 510static int ast_dp501_connector_helper_get_modes(struct drm_connector *connector)511{512	struct ast_connector *ast_connector = to_ast_connector(connector);513	int count;514 515	if (ast_connector->physical_status == connector_status_connected) {516		struct ast_device *ast = to_ast_device(connector->dev);517		const struct drm_edid *drm_edid;518 519		drm_edid = drm_edid_read_custom(connector, ast_dp512_read_edid_block, ast);520		drm_edid_connector_update(connector, drm_edid);521		count = drm_edid_connector_add_modes(connector);522		drm_edid_free(drm_edid);523	} else {524		drm_edid_connector_update(connector, NULL);525 526		/*527		 * There's no EDID data without a connected monitor. Set BMC-528		 * compatible modes in this case. The XGA default resolution529		 * should work well for all BMCs.530		 */531		count = drm_add_modes_noedid(connector, 4096, 4096);532		if (count)533			drm_set_preferred_mode(connector, 1024, 768);534	}535 536	return count;537}538 539static int ast_dp501_connector_helper_detect_ctx(struct drm_connector *connector,540						 struct drm_modeset_acquire_ctx *ctx,541						 bool force)542{543	struct ast_connector *ast_connector = to_ast_connector(connector);544	struct ast_device *ast = to_ast_device(connector->dev);545	enum drm_connector_status status = connector_status_disconnected;546 547	if (ast_dp501_is_connected(ast))548		status = connector_status_connected;549 550	if (status != ast_connector->physical_status)551		++connector->epoch_counter;552	ast_connector->physical_status = status;553 554	return connector_status_connected;555}556 557static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = {558	.get_modes = ast_dp501_connector_helper_get_modes,559	.detect_ctx = ast_dp501_connector_helper_detect_ctx,560};561 562static const struct drm_connector_funcs ast_dp501_connector_funcs = {563	.reset = drm_atomic_helper_connector_reset,564	.fill_modes = drm_helper_probe_single_connector_modes,565	.destroy = drm_connector_cleanup,566	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,567	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,568};569 570static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector *connector)571{572	int ret;573 574	ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs,575				 DRM_MODE_CONNECTOR_DisplayPort);576	if (ret)577		return ret;578 579	drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs);580 581	connector->interlace_allowed = 0;582	connector->doublescan_allowed = 0;583 584	connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;585 586	return 0;587}588 589int ast_dp501_output_init(struct ast_device *ast)590{591	struct drm_device *dev = &ast->base;592	struct drm_crtc *crtc = &ast->crtc;593	struct drm_encoder *encoder = &ast->output.dp501.encoder;594	struct ast_connector *ast_connector = &ast->output.dp501.connector;595	struct drm_connector *connector = &ast_connector->base;596	int ret;597 598	ret = drm_encoder_init(dev, encoder, &ast_dp501_encoder_funcs,599			       DRM_MODE_ENCODER_TMDS, NULL);600	if (ret)601		return ret;602	drm_encoder_helper_add(encoder, &ast_dp501_encoder_helper_funcs);603 604	encoder->possible_crtcs = drm_crtc_mask(crtc);605 606	ret = ast_dp501_connector_init(dev, connector);607	if (ret)608		return ret;609	ast_connector->physical_status = connector->status;610 611	ret = drm_connector_attach_encoder(connector, encoder);612	if (ret)613		return ret;614 615	return 0;616}617