/*
 * SPDX-License-Identifier:     GPL-2.0+
 *
 * (C) Copyright 2022 Rockchip Electronics Co., Ltd
 */

#include <common.h>
#include <asm/io.h>
#include <dwc3-uboot.h>
#include <video_rockchip.h>

DECLARE_GLOBAL_DATA_PTR;

/*
 * ==================== USB VBUS 检测 ====================
 * USB_VBUSDET (SoC引脚25) → USB 2.0 PHY → utmi_bvalid
 * 寄存器: PERI_GRF (0xff000000) + 0x60 bit 9
 * 来源: drivers/phy/phy-rockchip-inno-usb2.c
 *
 * ==================== 电源按键 ====================
 * GPIO0_A3 (SoC引脚65) = 电源按键, 按下为低电平
 * GPIO0_A2 (SoC引脚64) = 电源保持, 拉高后维持供电
 * 对应 DT uboot-charge 节点:
 *   power-key-gpios  = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>
 *   power-hold-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>
 *
 * GPIO3_B7 (SoC引脚124) = 充电芯片 NSTDBY, 低电平=充满
 */
#define PERI_GRF_BASE		0xff000000
#define USB_UTMI_BVALID_OFF	0x0060
#define USB_UTMI_BVALID_BIT	BIT(9)

#define GPIO0_BASE		0xff380000
#define GPIO0_DR_L		0x0000
#define GPIO0_DDR_L		0x0008
#define GPIO0_EXT_PORT		0x0070
#define GPIO0_A2		2
#define GPIO0_A3		3
#define GPIO0_A2_MASK		(1 << GPIO0_A2)
#define GPIO0_A3_MASK		(1 << GPIO0_A3)

#define PMU_IOC_BASE		0xff388000
#define GPIO0A_IOMUX_SEL_L	0x00
#define GPIO0_A2_IOMUX_BIT	8	/* bits[11:8] */
#define GPIO0_A3_IOMUX_BIT	12	/* bits[15:12] */

#define GPIO3_BASE		0xff550000
#define GPIO3_B7_MASK		(1 << 15)

/* V2 GPIO 读写宏(与 drivers/gpio/rk_gpio.c 一致) */
#define gpio_v2_read(addr)	(readl(addr) & 0xFFFF)
#define gpio_v2_write(addr, val)	writel((val) | 0xFFFF0000, addr)

static int check_usb_powered(void)
{
	u32 val = readl(PERI_GRF_BASE + USB_UTMI_BVALID_OFF);
	return (val & USB_UTMI_BVALID_BIT) ? 1 : 0;
}

static int read_nstdby(void)
{
	u32 val = readl(GPIO3_BASE + GPIO0_EXT_PORT);
	return (val & GPIO3_B7_MASK) ? 1 : 0;
}

/* 配置电源按键和电源保持引脚 */
static void power_gpio_init(void)
{
	/* IOMUX: GPIO0_A2/A3 设为 GPIO 功能(function 0)*/
	writel((0xFF << (GPIO0_A2_IOMUX_BIT + 16)) |
	       (0 << GPIO0_A2_IOMUX_BIT) |
	       (0 << GPIO0_A3_IOMUX_BIT),
	       PMU_IOC_BASE + GPIO0A_IOMUX_SEL_L);

	/* DDR: A3=输入(按键), A2=输出(电源保持), 初始低 */
	u32 ddr = gpio_v2_read(GPIO0_BASE + GPIO0_DDR_L);
	ddr |= GPIO0_A2_MASK;		/* A2 = output */
	ddr &= ~GPIO0_A3_MASK;		/* A3 = input */
	gpio_v2_write(GPIO0_BASE + GPIO0_DDR_L, ddr);

	/* DR: A2 = low(不供电)*/
	u32 dr = gpio_v2_read(GPIO0_BASE + GPIO0_DR_L);
	dr &= ~GPIO0_A2_MASK;
	gpio_v2_write(GPIO0_BASE + GPIO0_DR_L, dr);
}

/* 拉高 A2 保持供电 */
static void power_hold_on(void)
{
	u32 dr = gpio_v2_read(GPIO0_BASE + GPIO0_DR_L);
	dr |= GPIO0_A2_MASK;
	gpio_v2_write(GPIO0_BASE + GPIO0_DR_L, dr);
	printf("[PWR] Power hold enabled\n");
}

/* 读按键状态: 按下=低电平, 返回 1=按下 */
static int power_key_pressed(void)
{
	u32 ext = readl(GPIO0_BASE + GPIO0_EXT_PORT);
	return (ext & GPIO0_A3_MASK) ? 0 : 1;
}

/*
 * 充电+电源按键逻辑:
 *   有 USB 供电时进入, 轮询按键和 USB 拔出
 *   按键按下 2 秒 → 拉高 A2 保持供电 → 退出启动内核
 *   USB 拔出 → 直接退出(若无 A2 保持则硬件掉电)
 */
static void show_charge_logo(void)
{
	int charging = read_nstdby();
	int last_charging = charging;
	int battery_level = 0;  /* 0, 1, 2, 3, 4 → 0%, 25%, 50%, 75%, 100% */
	static const char *bmp_names[] = {
		"battery_0.bmp", "battery_25.bmp", "battery_50.bmp",
		"battery_75.bmp", "battery_100.bmp"
	};

	printf("\n[%s] USB Powered\n",
	       charging ? "CHARGING" : "FULL");

	power_gpio_init();

	/*
	 * USB 检测只需要上电时判断这一次。
	 * 进入循环后不再反复读 USB 寄存器 —— USB 拔出后硬件无 power_hold 自然掉电,
	 * 无需软件检测。
	 */

	/* === 按键开机 === */
	if (power_key_pressed()) {
		/*
		 * 上电到进入此函数时按键仍按着——用户从上电一直按到现在,
		 * 已超过 2 秒,直接开机,无需再等。
		 */
		printf("[PWR] Key held since power-on, boot now\n");
		power_hold_on();
		goto exit;
	}

	printf("[PWR] No key press, charge mode\n");

	/* 显示当前电量图片(图片找不到也不影响后续流程)*/
	rockchip_show_bmp(bmp_names[battery_level]);

	while (1) {
		/* 充电状态变化时重置电量指示 */
		if (read_nstdby() != last_charging) {
			last_charging = !last_charging;
			battery_level = last_charging ? 4 : 0;
			printf("[%s] state changed\n",
			       last_charging ? "CHARGING" : "FULL");
			rockchip_show_bmp(bmp_names[battery_level]);
		}

		/* 每 3 秒递增电量指示(充满则停在 100%) */
		if (last_charging) {
			/* charging: 0% → 25% → 50% → 75% → repeat */
			battery_level = (battery_level + 1) % 4;
		} /* else full: 停在 100%,不循环 */

		rockchip_show_bmp(bmp_names[battery_level]);

		/* 等待 3 秒,期间检测按键长按 2s 开机 */
		{
			u32 start = get_timer(0);
			u32 key_start = 0;
			bool key_was_down = false;

			while (get_timer(start) < 3000) {
				mdelay(10);

				if (power_key_pressed()) {
					if (!key_was_down) {
						key_was_down = true;
						key_start = get_timer(0);
					} else if (get_timer(key_start) >= 2000) {
						printf("[PWR] Long press, booting...\n");
						power_hold_on();
						goto exit;
					}
				} else {
					key_was_down = false;
				}
			}
		}
	}

exit:
	printf("[CHARGE] Boot...\n");
}


int rk_board_late_init(void)
{
	if (check_usb_powered()) {
		printf("[CHARGE] USB Power detected!\n");
		show_charge_logo();
	}

	return 0;
}