Loading...
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright 2025 NXP
 */

#include <env.h>
#include <asm/arch/sys_proto.h>
#include <i2c.h>
#include <dm.h>

#define TCPC_ALERT 0x10
#define TCPC_ALERT_MASK 0x12
#define TCPC_FAULT_STATUS_MASK 0x15
#define USB_I2C_BUS 2
#define USB_I2C_ADDR 0x50

/*
 * Since tcpc driver is not upstream. PTN5110 interrupt will cause
 * kernel panic because nobody cares the interrupt. So add workaround here.
 * Clear PTN5110 USB Power Delivery controller alert status by
 * masking interrupts and clearing pending alerts via I2C communication.
 * This is typically called during board initialization to ensure the USB PD
 * controller starts in a clean state without any stale alert conditions.
 */
static int clear_pd_alert(void)
{
	struct udevice *bus;
	struct udevice *i2c_dev = NULL;
	int ret;
	u8 buffer_0[2] = {0, 0};
	u8 buffer_1[2] = {0xff, 0xff};

	ret = uclass_get_device_by_seq(UCLASS_I2C, USB_I2C_BUS, &bus);
	if (ret) {
		printf("Failed to get I2C bus %d\n", USB_I2C_BUS);
		return ret;
	}

	ret = dm_i2c_probe(bus, USB_I2C_ADDR, 0, &i2c_dev);
	if (ret) {
		printf("Can't find USB PD device at 0x%02x\n", USB_I2C_ADDR);
		return ret;
	}

	/* Mask all alert status*/
	ret = dm_i2c_write(i2c_dev, TCPC_ALERT_MASK, buffer_0, 2);
	if (ret) {
		printf("%s dm_i2c_write failed: %d\n", __func__, ret);
		return ret;
	}

	ret = dm_i2c_write(i2c_dev, TCPC_FAULT_STATUS_MASK, buffer_0, 2);
	if (ret) {
		printf("%s dm_i2c_write failed: %d\n", __func__, ret);
		return ret;
	}

	ret = dm_i2c_write(i2c_dev, TCPC_ALERT, buffer_1, 2);
	if (ret) {
		printf("%s dm_i2c_write failed: %d\n", __func__, ret);
		return ret;
	}

	return 0;
}

int board_late_init(void)
{
	if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
		board_late_mmc_env_init();

	env_set("sec_boot", "no");

	if (IS_ENABLED(CONFIG_AHAB_BOOT))
		env_set("sec_boot", "yes");

	if (IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG)) {
		env_set("board_name", "11X11_FRDM");
		env_set("board_rev", "iMX91");
	}

	clear_pd_alert();
	return 0;
}